Autogenerated HTML docs for v1.8.0-251-g3a189
diff --git a/RelNotes/1.8.0.1.txt b/RelNotes/1.8.0.1.txt index 6c487c3..cda8b3e 100644 --- a/RelNotes/1.8.0.1.txt +++ b/RelNotes/1.8.0.1.txt
@@ -43,4 +43,10 @@ transport ended up sleeping for minutes in select(2) system call. A workaround has been added for this. -Also contains minor fixes and documentation updates. + * Various rfc2047 quoting issues around a non-ASCII name on the + From: line in the output from format-patch have been corrected. + + * "git diff -G<pattern>" did not honor textconv filter when looking + for changes. + +Also contains other minor fixes and documentation updates.
diff --git a/RelNotes/1.8.1.txt b/RelNotes/1.8.1.txt index 107e5f3..00d728d 100644 --- a/RelNotes/1.8.1.txt +++ b/RelNotes/1.8.1.txt
@@ -32,16 +32,22 @@ The bug has been fixed in "less" version 406 (June 2007), and the workaround has been removed in this release. + * Some documentation pages that used to ship only in the plain text + format are now formatted in HTML as well. + * A new configuration variable "diff.context" can be used to give the default number of context lines in the patch output, to override the hardcoded default of 3 lines. - * "git format-patch" leraned the "--notes=<ref>" option to give + * "git format-patch" learned the "--notes=<ref>" option to give notes for the commit after the three-dash lines in its output. * "git log --grep=<pcre>" learned to honor the "grep.patterntype" configuration set to "perl". + * "git replace -d <object>" now interprets <object>, instead of only + accepting full hex object name. + * "git rm $submodule" used to punt on removing a submodule working tree to avoid losing the repository embedded in it. Because recent git uses a mechanism to separate the submodule repository @@ -70,6 +76,8 @@ Performance, Internal Implementation, etc. + * Compilation on Cygwin with newer header files are supported now. + * The logic to generate the initial advertisement from "upload-pack" (what is invoked by "git fetch" on the other side of the connection) to list what refs are available in the @@ -78,6 +86,10 @@ * The logic to find set of attributes that match a given path has been optimized. + * Use preloadindex in "git diff-index" and "git update-index", which + has a nice speedup on systems with slow stat calls (and even on + Linux). + Also contains minor documentation updates and code clean-ups. @@ -132,11 +144,11 @@ (merge 11fbe18 po/maint-refs-replace-docs later to maint). * Various rfc2047 quoting issues around a non-ASCII name on the - From: line in the output from format-patch has been corrected. + From: line in the output from format-patch have been corrected. (merge 25dc8da js/format-2047 later to maint). * Sometimes curl_multi_timeout() function suggested a wrong timeout - value when there is no file descriptors to wait on and the http + value when there is no file descriptor to wait on and the http transport ended up sleeping for minutes in select(2) system call. A workaround has been added for this. (merge 7202b81 sz/maint-curl-multi-timeout later to maint). @@ -149,3 +161,27 @@ * "git diff -G<pattern>" did not honor textconv filter when looking for changes. (merge b1c2f57 jk/maint-diff-grep-textconv later to maint). + + * Some HTTP servers ask for auth only during the actual packing phase + (not in ls-remote phase); this is not really a recommended + configuration, but the clients used to fail to authenticate with + such servers. + (merge 2e736fd jk/maint-http-half-auth-fetch later to maint). + + * "git p4" used to try expanding malformed "$keyword$" that spans + across multiple lines. + (merge 6b2bf41 pw/maint-p4-rcs-expansion-newline later to maint). + + * Syntax highlighting in "gitweb" was not quite working. + (merge 048b399 rh/maint-gitweb-highlight-ext later to maint). + + * RSS feed from "gitweb" had a xss hole in its title output. + (merge 0f0ecf6 jk/maint-gitweb-xss later to maint). + + * "git config --path $key" segfaulted on "[section] key" (a boolean + "true" spelled without "=", not "[section] key = true"). + (merge 962c38e cn/config-missing-path later to maint). + + * "git checkout -b foo" while on an unborn branch did not say + "Switched to a new branch 'foo'" like other cases. + (merge afa8c07 jk/checkout-out-of-unborn later to maint).
diff --git a/git-bisect-lk2009.html b/git-bisect-lk2009.html index fcfd283..1d9798a 100644 --- a/git-bisect-lk2009.html +++ b/git-bisect-lk2009.html
@@ -777,7 +777,7 @@ Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile</tt></pre> +:100644 100644 5cf82581... 4492984e... M Makefile</tt></pre> </div></div> <div class="paragraph"><p>At this point we can see what the commit does, check it out (if it’s not already checked out) or tinker with it, for example:</p></div> @@ -846,7 +846,7 @@ Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile +:100644 100644 5cf82581... 4492984e... M Makefile bisect run success</tt></pre> </div></div> <div class="paragraph"><p>In this example, we passed "grep <em>^SUBLEVEL = 25</em> Makefile" as @@ -1729,7 +1729,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2011-11-15 13:45:02 PDT +Last updated 2012-11-20 13:06:02 PDT </div> </div> </body>
diff --git a/git-bisect-lk2009.txt b/git-bisect-lk2009.txt index 8a2ba37..ec4497e 100644 --- a/git-bisect-lk2009.txt +++ b/git-bisect-lk2009.txt
@@ -257,7 +257,7 @@ Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile +:100644 100644 5cf82581... 4492984e... M Makefile ------------- At this point we can see what the commit does, check it out (if it's @@ -331,7 +331,7 @@ Linux 2.6.26-rc1 -:100644 100644 5cf8258195331a4dbdddff08b8d68642638eea57 4492984efc09ab72ff6219a7bc21fb6a957c4cd5 M Makefile +:100644 100644 5cf82581... 4492984e... M Makefile bisect run success -------------
diff --git a/git-fetch-pack.html b/git-fetch-pack.html index ce34d50..6136df7 100644 --- a/git-fetch-pack.html +++ b/git-fetch-pack.html
@@ -583,7 +583,10 @@ <h2 id="_synopsis">SYNOPSIS</h2> <div class="sectionbody"> <div class="verseblock"> -<div class="verseblock-content"><em>git fetch-pack</em> [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>…]</div> +<div class="verseblock-content"><em>git fetch-pack</em> [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] + [--upload-pack=<git-upload-pack>] + [--depth=<n>] [--no-progress] + [-v] [<host>:]<directory> [<refs>…]</div> <div class="verseblock-attribution"> </div></div> </div> @@ -758,7 +761,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2012-04-29 17:26:43 PDT +Last updated 2012-11-20 13:06:02 PDT </div> </div> </body>
diff --git a/git-fetch-pack.txt b/git-fetch-pack.txt index 474fa30..8c75120 100644 --- a/git-fetch-pack.txt +++ b/git-fetch-pack.txt
@@ -9,7 +9,10 @@ SYNOPSIS -------- [verse] -'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] [--no-progress] [-v] [<host>:]<directory> [<refs>...] +'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag] + [--upload-pack=<git-upload-pack>] + [--depth=<n>] [--no-progress] + [-v] [<host>:]<directory> [<refs>...] DESCRIPTION -----------
diff --git a/git-rm.html b/git-rm.html index 4df21a2..db5f343 100644 --- a/git-rm.html +++ b/git-rm.html
@@ -723,18 +723,6 @@ as well as modifications of existing paths.</p></div> <div class="paragraph"><p>Typically you would first remove all tracked files from the working tree using this command:</p></div> -<h3 id="_submodules">Submodules</h3><div style="clear:left"></div> -<div class="paragraph"><p>Only submodules using a gitfile (which means they were cloned -with a git version 1.7.8 or newer) will be removed from the work -tree, as their repository lives inside the .git directory of the -superproject. If a submodule (or one of those nested inside it) -still uses a .git directory, <tt>git rm</tt> will fail - no matter if forced -or not - to protect the submodule’s history.</p></div> -<div class="paragraph"><p>A submodule is considered up-to-date when the HEAD is the same as -recorded in the index, no tracked files are modified and no untracked -files that aren’t ignored are present in the submodules work tree. -Ignored files are deemed expendable and won’t stop a submodule’s work -tree from being removed.</p></div> <div class="listingblock"> <div class="content"> <pre><tt>git ls-files -z | xargs -0 rm -f</tt></pre> @@ -757,6 +745,18 @@ <div class="content"> <pre><tt>git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached</tt></pre> </div></div> +<h3 id="_submodules">Submodules</h3><div style="clear:left"></div> +<div class="paragraph"><p>Only submodules using a gitfile (which means they were cloned +with a git version 1.7.8 or newer) will be removed from the work +tree, as their repository lives inside the .git directory of the +superproject. If a submodule (or one of those nested inside it) +still uses a .git directory, <tt>git rm</tt> will fail - no matter if forced +or not - to protect the submodule’s history.</p></div> +<div class="paragraph"><p>A submodule is considered up-to-date when the HEAD is the same as +recorded in the index, no tracked files are modified and no untracked +files that aren’t ignored are present in the submodules work tree. +Ignored files are deemed expendable and won’t stop a submodule’s work +tree from being removed.</p></div> </div> <h2 id="_examples">EXAMPLES</h2> <div class="sectionbody"> @@ -797,7 +797,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2012-11-13 14:31:09 PDT +Last updated 2012-11-20 13:06:02 PDT </div> </div> </body>
diff --git a/git-rm.txt b/git-rm.txt index 882cb11..262436b 100644 --- a/git-rm.txt +++ b/git-rm.txt
@@ -107,21 +107,6 @@ Typically you would first remove all tracked files from the working tree using this command: -Submodules -~~~~~~~~~~ -Only submodules using a gitfile (which means they were cloned -with a git version 1.7.8 or newer) will be removed from the work -tree, as their repository lives inside the .git directory of the -superproject. If a submodule (or one of those nested inside it) -still uses a .git directory, `git rm` will fail - no matter if forced -or not - to protect the submodule's history. - -A submodule is considered up-to-date when the HEAD is the same as -recorded in the index, no tracked files are modified and no untracked -files that aren't ignored are present in the submodules work tree. -Ignored files are deemed expendable and won't stop a submodule's work -tree from being removed. - ---------------- git ls-files -z | xargs -0 rm -f ---------------- @@ -149,6 +134,21 @@ git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached ---------------- +Submodules +~~~~~~~~~~ +Only submodules using a gitfile (which means they were cloned +with a git version 1.7.8 or newer) will be removed from the work +tree, as their repository lives inside the .git directory of the +superproject. If a submodule (or one of those nested inside it) +still uses a .git directory, `git rm` will fail - no matter if forced +or not - to protect the submodule's history. + +A submodule is considered up-to-date when the HEAD is the same as +recorded in the index, no tracked files are modified and no untracked +files that aren't ignored are present in the submodules work tree. +Ignored files are deemed expendable and won't stop a submodule's work +tree from being removed. + EXAMPLES -------- `git rm Documentation/\*.txt`::
diff --git a/howto-index.html b/howto-index.html index 3ffa768..0c3e45c 100644 --- a/howto-index.html +++ b/howto-index.html
@@ -561,7 +561,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/maintain-git.txt">maintain-git</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> +<a href="howto/maintain-git.html">maintain-git</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> </p> </li> </ul></div> @@ -572,7 +572,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/rebase-from-internal-branch.txt">rebase-from-internal-branch</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> +<a href="howto/rebase-from-internal-branch.html">rebase-from-internal-branch</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> </p> </li> </ul></div> @@ -584,7 +584,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/rebuild-from-update-hook.txt">rebuild-from-update-hook</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> +<a href="howto/rebuild-from-update-hook.html">rebuild-from-update-hook</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> </p> </li> </ul></div> @@ -594,7 +594,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/recover-corrupted-blob-object.txt">recover-corrupted-blob-object</a> by Linus Torvalds <<a href="mailto:torvalds@linux-foundation.org">torvalds@linux-foundation.org</a>> +<a href="howto/recover-corrupted-blob-object.html">recover-corrupted-blob-object</a> by Linus Torvalds <<a href="mailto:torvalds@linux-foundation.org">torvalds@linux-foundation.org</a>> </p> </li> </ul></div> @@ -603,7 +603,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/revert-a-faulty-merge.txt">revert-a-faulty-merge</a> by Linus Torvalds <<a href="mailto:torvalds@linux-foundation.org">torvalds@linux-foundation.org</a>>, Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> +<a href="howto/revert-a-faulty-merge.html">revert-a-faulty-merge</a> by Linus Torvalds <<a href="mailto:torvalds@linux-foundation.org">torvalds@linux-foundation.org</a>>, Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> </p> </li> </ul></div> @@ -624,7 +624,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/separating-topic-branches.txt">separating-topic-branches</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> +<a href="howto/separating-topic-branches.html">separating-topic-branches</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> </p> </li> </ul></div> @@ -632,12 +632,12 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/setup-git-server-over-http.txt">setup-git-server-over-http</a> by Rutger Nijlunsing <<a href="mailto:rutger@nospam.com">rutger@nospam.com</a>> +<a href="howto/setup-git-server-over-http.html">setup-git-server-over-http</a> by Rutger Nijlunsing <<a href="mailto:rutger@nospam.com">rutger@nospam.com</a>> </p> </li> <li> <p> -<a href="howto/update-hook-example.txt">update-hook-example</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> and Carl Baldwin <<a href="mailto:cnb@fc.hp.com">cnb@fc.hp.com</a>> +<a href="howto/update-hook-example.html">update-hook-example</a> by Junio C Hamano <<a href="mailto:gitster@pobox.com">gitster@pobox.com</a>> and Carl Baldwin <<a href="mailto:cnb@fc.hp.com">cnb@fc.hp.com</a>> </p> </li> </ul></div> @@ -647,7 +647,7 @@ <div class="ulist"><ul> <li> <p> -<a href="howto/use-git-daemon.txt">use-git-daemon</a> +<a href="howto/use-git-daemon.html">use-git-daemon</a> </p> </li> <li> @@ -675,7 +675,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2012-10-21 14:59:35 PDT +Last updated 2012-11-20 13:06:03 PDT </div> </div> </body>
diff --git a/howto-index.txt b/howto-index.txt index a1f7beb..603b926 100644 --- a/howto-index.txt +++ b/howto-index.txt
@@ -4,7 +4,7 @@ Here is a collection of mailing list postings made by various people describing how they use git in their workflow. -* link:howto/maintain-git.txt[maintain-git] by Junio C Hamano <gitster@pobox.com> +* link:howto/maintain-git.html[maintain-git] by Junio C Hamano <gitster@pobox.com> Imagine that git development is racing along as usual, when our friendly neighborhood maintainer is struck down by a wayward bus. Out of the @@ -12,7 +12,7 @@ step up as the new maintainer. This howto will show you "how to" do it. -* link:howto/rebase-from-internal-branch.txt[rebase-from-internal-branch] by Junio C Hamano <gitster@pobox.com> +* link:howto/rebase-from-internal-branch.html[rebase-from-internal-branch] by Junio C Hamano <gitster@pobox.com> In this article, JC talks about how he rebases the public "pu" branch using the core GIT tools when he updates @@ -21,20 +21,20 @@ upstream. -* link:howto/rebuild-from-update-hook.txt[rebuild-from-update-hook] by Junio C Hamano <gitster@pobox.com> +* link:howto/rebuild-from-update-hook.html[rebuild-from-update-hook] by Junio C Hamano <gitster@pobox.com> In this how-to article, JC talks about how he uses the post-update hook to automate git documentation page shown at http://www.kernel.org/pub/software/scm/git/docs/. -* link:howto/recover-corrupted-blob-object.txt[recover-corrupted-blob-object] by Linus Torvalds <torvalds@linux-foundation.org> +* link:howto/recover-corrupted-blob-object.html[recover-corrupted-blob-object] by Linus Torvalds <torvalds@linux-foundation.org> Some tricks to reconstruct blob objects in order to fix a corrupted repository. -* link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge] by Linus Torvalds <torvalds@linux-foundation.org>, Junio C Hamano <gitster@pobox.com> +* link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge] by Linus Torvalds <torvalds@linux-foundation.org>, Junio C Hamano <gitster@pobox.com> Sometimes a branch that was already merged to the mainline is later found to be faulty. Linus and Junio give guidance on @@ -49,23 +49,23 @@ and easier sanity checking. -* link:howto/separating-topic-branches.txt[separating-topic-branches] by Junio C Hamano <gitster@pobox.com> +* link:howto/separating-topic-branches.html[separating-topic-branches] by Junio C Hamano <gitster@pobox.com> In this article, JC describes how to separate topic branches. -* link:howto/setup-git-server-over-http.txt[setup-git-server-over-http] by Rutger Nijlunsing <rutger@nospam.com> +* link:howto/setup-git-server-over-http.html[setup-git-server-over-http] by Rutger Nijlunsing <rutger@nospam.com> -* link:howto/update-hook-example.txt[update-hook-example] by Junio C Hamano <gitster@pobox.com> and Carl Baldwin <cnb@fc.hp.com> +* link:howto/update-hook-example.html[update-hook-example] by Junio C Hamano <gitster@pobox.com> and Carl Baldwin <cnb@fc.hp.com> An example hooks/update script is presented to implement repository maintenance policies, such as who can push into which branch and who can make a tag. -* link:howto/use-git-daemon.txt[use-git-daemon] +* link:howto/use-git-daemon.html[use-git-daemon]
diff --git a/howto/maintain-git.html b/howto/maintain-git.html new file mode 100644 index 0000000..08ee0c1 --- /dev/null +++ b/howto/maintain-git.html
@@ -0,0 +1,1031 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to maintain Git</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to maintain Git</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>The maintainer’s git time is spent on three activities.</p></div> +<div class="ulist"><ul> +<li> +<p> +Communication (60%) +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>Mailing list discussions on general design, fielding user +questions, diagnosing bug reports; reviewing, commenting on, +suggesting alternatives to, and rejecting patches.</tt></pre> +</div></div> +</li> +<li> +<p> +Integration (30%) +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>Applying new patches from the contributors while spotting and +correcting minor mistakes, shuffling the integration and +testing branches, pushing the results out, cutting the +releases, and making announcements.</tt></pre> +</div></div> +</li> +<li> +<p> +Own development (10%) +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>Scratching my own itch and sending proposed patch series out.</tt></pre> +</div></div> +</li> +</ul></div> +<div class="paragraph"><p>The policy on Integration is informally mentioned in "A Note +from the maintainer" message, which is periodically posted to +this mailing list after each feature release is made.</p></div> +<div class="paragraph"><p>The policy.</p></div> +<div class="ulist"><ul> +<li> +<p> +Feature releases are numbered as vX.Y.Z and are meant to + contain bugfixes and enhancements in any area, including + functionality, performance and usability, without regression. +</p> +</li> +<li> +<p> +Maintenance releases are numbered as vX.Y.Z.W and are meant + to contain only bugfixes for the corresponding vX.Y.Z feature + release and earlier maintenance releases vX.Y.Z.V (V < W). +</p> +</li> +<li> +<p> +<em>master</em> branch is used to prepare for the next feature + release. In other words, at some point, the tip of <em>master</em> + branch is tagged with vX.Y.Z. +</p> +</li> +<li> +<p> +<em>maint</em> branch is used to prepare for the next maintenance + release. After the feature release vX.Y.Z is made, the tip + of <em>maint</em> branch is set to that release, and bugfixes will + accumulate on the branch, and at some point, the tip of the + branch is tagged with vX.Y.Z.1, vX.Y.Z.2, and so on. +</p> +</li> +<li> +<p> +<em>next</em> branch is used to publish changes (both enhancements + and fixes) that (1) have worthwhile goal, (2) are in a fairly + good shape suitable for everyday use, (3) but have not yet + demonstrated to be regression free. New changes are tested + in <em>next</em> before merged to <em>master</em>. +</p> +</li> +<li> +<p> +<em>pu</em> branch is used to publish other proposed changes that do + not yet pass the criteria set for <em>next</em>. +</p> +</li> +<li> +<p> +The tips of <em>master</em>, <em>maint</em> and <em>next</em> branches will always + fast-forward, to allow people to build their own + customization on top of them. +</p> +</li> +<li> +<p> +Usually <em>master</em> contains all of <em>maint</em>, <em>next</em> contains all + of <em>master</em> and <em>pu</em> contains all of <em>next</em>. +</p> +</li> +<li> +<p> +The tip of <em>master</em> is meant to be more stable than any + tagged releases, and the users are encouraged to follow it. +</p> +</li> +<li> +<p> +The <em>next</em> branch is where new action takes place, and the + users are encouraged to test it so that regressions and bugs + are found before new topics are merged to <em>master</em>. +</p> +</li> +</ul></div> +<div class="paragraph"><p>A typical git day for the maintainer implements the above policy +by doing the following:</p></div> +<div class="ulist"><ul> +<li> +<p> +Scan mailing list and #git channel log. Respond with review + comments, suggestions etc. Kibitz. Collect potentially + usable patches from the mailing list. Patches about a single + topic go to one mailbox (I read my mail in Gnus, and type + \C-o to save/append messages in files in mbox format). +</p> +</li> +<li> +<p> +Review the patches in the saved mailboxes. Edit proposed log + message for typofixes and clarifications, and add Acks + collected from the list. Edit patch to incorporate "Oops, + that should have been like this" fixes from the discussion. +</p> +</li> +<li> +<p> +Classify the collected patches and handle <em>master</em> and + <em>maint</em> updates: +</p> +</li> +<li> +<p> +Obviously correct fixes that pertain to the tip of <em>maint</em> + are directly applied to <em>maint</em>. +</p> +</li> +<li> +<p> +Obviously correct fixes that pertain to the tip of <em>master</em> + are directly applied to <em>master</em>. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>This step is done with "git am".</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout master ;# or "git checkout maint" +$ git am -3 -s mailbox +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +Merge downwards (maint→master): +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout master +$ git merge maint +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +Review the last issue of "What’s cooking" message, review the + topics scheduled for merging upwards (topic→master and + topic→maint), and merge. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout master ;# or "git checkout maint" +$ git merge ai/topic ;# or "git merge ai/maint-topic" +$ git log -p ORIG_HEAD.. ;# final review +$ git diff ORIG_HEAD.. ;# final review +$ make test ;# final review +$ git branch -d ai/topic ;# or "git branch -d ai/maint-topic"</tt></pre> +</div></div> +</li> +<li> +<p> +Merge downwards (maint→master) if needed: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout master +$ git merge maint +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +Merge downwards (master→next) if needed: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout next +$ git merge master +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +Handle the remaining patches: +</p> +</li> +<li> +<p> +Anything unobvious that is applicable to <em>master</em> (in other + words, does not depend on anything that is still in <em>next</em> + and not in <em>master</em>) is applied to a new topic branch that + is forked from the tip of <em>master</em>. This includes both + enhancements and unobvious fixes to <em>master</em>. A topic + branch is named as ai/topic where "ai" is typically + author’s initial and "topic" is a descriptive name of the + topic (in other words, "what’s the series is about"). +</p> +</li> +<li> +<p> +An unobvious fix meant for <em>maint</em> is applied to a new + topic branch that is forked from the tip of <em>maint</em>. The + topic is named as ai/maint-topic. +</p> +</li> +<li> +<p> +Changes that pertain to an existing topic are applied to + the branch, but: +</p> +</li> +<li> +<p> +obviously correct ones are applied first; +</p> +</li> +<li> +<p> +questionable ones are discarded or applied to near the tip; +</p> +</li> +<li> +<p> +Replacement patches to an existing topic are accepted only + for commits not in <em>next</em>. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>The above except the "replacement" are all done with:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git am -3 -s mailbox</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>while patch replacement is often done by:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git format-patch ai/topic~$n..ai/topic ;# export existing</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>then replace some parts with the new patch, and reapplying:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git reset --hard ai/topic~$n +$ git am -3 -s 000*.txt</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The full test suite is always run for 'maint' and 'master' +after patch application; for topic branches the tests are run +as time permits.</tt></pre> +</div></div> +</li> +<li> +<p> +Update "What’s cooking" message to review the updates to + existing topics, newly added topics and graduated topics. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>This step is helped with Meta/cook script (where Meta/ contains +a checkout of the 'todo' branch).</tt></pre> +</div></div> +</li> +<li> +<p> +Merge topics to <em>next</em>. For each branch whose tip is not + merged to <em>next</em>, one of three things can happen: +</p> +</li> +<li> +<p> +The commits are all next-worthy; merge the topic to next: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout next +$ git merge ai/topic ;# or "git merge ai/maint-topic" +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +The new parts are of mixed quality, but earlier ones are + next-worthy; merge the early parts to next: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout next +$ git merge ai/topic~2 ;# the tip two are dubious +$ make test</tt></pre> +</div></div> +</li> +<li> +<p> +Nothing is next-worthy; do not do anything. +</p> +</li> +<li> +<p> +[<strong> OBSOLETE </strong>] Optionally rebase topics that do not have any commit + in next yet, when they can take advantage of low-level framework + change that is merged to <em>master</em> already. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git rebase master ai/topic</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>This step is helped with Meta/git-topic.perl script to +identify which topic is rebaseable. There also is a +pre-rebase hook to make sure that topics that are already in +'next' are not rebased beyond the merged commit.</tt></pre> +</div></div> +</li> +<li> +<p> +[<strong> OBSOLETE </strong>] Rebuild "pu" to merge the tips of topics not in <em>next</em>. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout pu +$ git reset --hard next +$ git merge ai/topic ;# repeat for all remaining topics +$ make test</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>This step is helped with Meta/PU script</tt></pre> +</div></div> +</li> +<li> +<p> +Push four integration branches to a private repository at + k.org and run "make test" on all of them. +</p> +</li> +<li> +<p> +Push four integration branches to /pub/scm/git/git.git at + k.org. This triggers its post-update hook which: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>(1) runs "git pull" in $HOME/git-doc/ repository to pull + 'master' just pushed out;</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(2) runs "make doc" in $HOME/git-doc/, install the generated + documentation in staging areas, which are separate + repositories that have html and man branches checked + out.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(3) runs "git commit" in the staging areas, and run "git + push" back to /pub/scm/git/git.git/ to update the html + and man branches.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(4) installs generated documentation to /pub/software/scm/git/docs/ + to be viewed from http://www.kernel.org/</tt></pre> +</div></div> +</li> +<li> +<p> +Fetch html and man branches back from k.org, and push four + integration branches and the two documentation branches to + repo.or.cz and other mirrors. +</p> +</li> +</ul></div> +<div class="paragraph"><p>Some observations to be made.</p></div> +<div class="ulist"><ul> +<li> +<p> +Each topic is tested individually, and also together with + other topics cooking in <em>next</em>. Until it matures, none part + of it is merged to <em>master</em>. +</p> +</li> +<li> +<p> +A topic already in <em>next</em> can get fixes while still in + <em>next</em>. Such a topic will have many merges to <em>next</em> (in + other words, "git log --first-parent next" will show many + "Merge ai/topic to next" for the same topic. +</p> +</li> +<li> +<p> +An unobvious fix for <em>maint</em> is cooked in <em>next</em> and then + merged to <em>master</em> to make extra sure it is Ok and then + merged to <em>maint</em>. +</p> +</li> +<li> +<p> +Even when <em>next</em> becomes empty (in other words, all topics + prove stable and are merged to <em>master</em> and "git diff master + next" shows empty), it has tons of merge commits that will + never be in <em>master</em>. +</p> +</li> +<li> +<p> +In principle, "git log --first-parent master..next" should + show nothing but merges (in practice, there are fixup commits + and reverts that are not merges). +</p> +</li> +<li> +<p> +Commits near the tip of a topic branch that are not in <em>next</em> + are fair game to be discarded, replaced or rewritten. + Commits already merged to <em>next</em> will not be. +</p> +</li> +<li> +<p> +Being in the <em>next</em> branch is not a guarantee for a topic to + be included in the next feature release. Being in the + <em>master</em> branch typically is. +</p> +</li> +</ul></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:08 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/maintain-git.txt b/howto/maintain-git.txt index 8823a37..ea6e4a5 100644 --- a/howto/maintain-git.txt +++ b/howto/maintain-git.txt
@@ -5,6 +5,10 @@ neighborhood maintainer is struck down by a wayward bus. Out of the hordes of suckers (loyal developers), you have been tricked (chosen) to step up as the new maintainer. This howto will show you "how to" do it. +Content-type: text/asciidoc + +How to maintain Git +=================== The maintainer's git time is spent on three activities.
diff --git a/howto/rebase-from-internal-branch.html b/howto/rebase-from-internal-branch.html new file mode 100644 index 0000000..e4cb9e0 --- /dev/null +++ b/howto/rebase-from-internal-branch.html
@@ -0,0 +1,718 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to rebase from an internal branch</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to rebase from an internal branch</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="listingblock"> +<div class="content"> +<pre><tt>Petr Baudis <pasky@suse.cz> writes: + +> Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter +> where Junio C Hamano <junkio@cox.net> told me that... +>> Linus Torvalds <torvalds@osdl.org> writes: +>> +>> > Junio, maybe you want to talk about how you move patches from your "pu" +>> > branch to the real branches. +>> +> Actually, wouldn't this be also precisely for what StGIT is intended to?</tt></pre> +</div></div> +<div class="paragraph"><p>Exactly my feeling. I was sort of waiting for Catalin to speak +up. With its basing philosophical ancestry on quilt, this is +the kind of task StGIT is designed to do.</p></div> +<div class="paragraph"><p>I just have done a simpler one, this time using only the core +GIT tools.</p></div> +<div class="paragraph"><p>I had a handful of commits that were ahead of master in pu, and I +wanted to add some documentation bypassing my usual habit of +placing new things in pu first. At the beginning, the commit +ancestry graph looked like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> *"pu" head +master --> #1 --> #2 --> #3</tt></pre> +</div></div> +<div class="paragraph"><p>So I started from master, made a bunch of edits, and committed:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout master +$ cd Documentation; ed git.txt ... +$ cd ..; git add Documentation/*.txt +$ git commit -s</tt></pre> +</div></div> +<div class="paragraph"><p>After the commit, the ancestry graph would look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> *"pu" head +master^ --> #1 --> #2 --> #3 + \ + \---> master</tt></pre> +</div></div> +<div class="paragraph"><p>The old master is now master^ (the first parent of the master). +The new master commit holds my documentation updates.</p></div> +<div class="paragraph"><p>Now I have to deal with "pu" branch.</p></div> +<div class="paragraph"><p>This is the kind of situation I used to have all the time when +Linus was the maintainer and I was a contributor, when you look +at "master" branch being the "maintainer" branch, and "pu" +branch being the "contributor" branch. Your work started at the +tip of the "maintainer" branch some time ago, you made a lot of +progress in the meantime, and now the maintainer branch has some +other commits you do not have yet. And "git rebase" was written +with the explicit purpose of helping to maintain branches like +"pu". You <em>could</em> merge master to pu and keep going, but if you +eventually want to cherrypick and merge some but not necessarily +all changes back to the master branch, it often makes later +operations for <em>you</em> easier if you rebase (i.e. carry forward +your changes) "pu" rather than merge. So I ran "git rebase":</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout pu +$ git rebase master pu</tt></pre> +</div></div> +<div class="paragraph"><p>What this does is to pick all the commits since the current +branch (note that I now am on "pu" branch) forked from the +master branch, and forward port these changes.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>master^ --> #1 --> #2 --> #3 + \ *"pu" head + \---> master --> #1' --> #2' --> #3'</tt></pre> +</div></div> +<div class="paragraph"><p>The diff between master^ and #1 is applied to master and +committed to create #1' commit with the commit information (log, +author and date) taken from commit #1. On top of that #2' and #3' +commits are made similarly out of #2 and #3 commits.</p></div> +<div class="paragraph"><p>Old #3 is not recorded in any of the .git/refs/heads/ file +anymore, so after doing this you will have dangling commit if +you ran fsck-cache, which is normal. After testing "pu", you +can run "git prune" to get rid of those original three commits.</p></div> +<div class="paragraph"><p>While I am talking about "git rebase", I should talk about how +to do cherrypicking using only the core GIT tools.</p></div> +<div class="paragraph"><p>Let’s go back to the earlier picture, with different labels.</p></div> +<div class="paragraph"><p>You, as an individual developer, cloned upstream repository and +made a couple of commits on top of it.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> *your "master" head +upstream --> #1 --> #2 --> #3</tt></pre> +</div></div> +<div class="paragraph"><p>You would want changes #2 and #3 incorporated in the upstream, +while you feel that #1 may need further improvements. So you +prepare #2 and #3 for e-mail submission.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git format-patch master^^ master</tt></pre> +</div></div> +<div class="paragraph"><p>This creates two files, 0001-XXXX.patch and 0002-XXXX.patch. Send +them out "To: " your project maintainer and "Cc: " your mailing +list. You could use contributed script git-send-email if +your host has necessary perl modules for this, but your usual +MUA would do as long as it does not corrupt whitespaces in the +patch.</p></div> +<div class="paragraph"><p>Then you would wait, and you find out that the upstream picked +up your changes, along with other changes.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> where *your "master" head +upstream --> #1 --> #2 --> #3 + used \ + to be \--> #A --> #2' --> #3' --> #B --> #C + *upstream head</tt></pre> +</div></div> +<div class="paragraph"><p>The two commits #2' and #3' in the above picture record the same +changes your e-mail submission for #2 and #3 contained, but +probably with the new sign-off line added by the upstream +maintainer and definitely with different committer and ancestry +information, they are different objects from #2 and #3 commits.</p></div> +<div class="paragraph"><p>You fetch from upstream, but not merge.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git fetch upstream</tt></pre> +</div></div> +<div class="paragraph"><p>This leaves the updated upstream head in .git/FETCH_HEAD but +does not touch your .git/HEAD nor .git/refs/heads/master. +You run "git rebase" now.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git rebase FETCH_HEAD master</tt></pre> +</div></div> +<div class="paragraph"><p>Earlier, I said that rebase applies all the commits from your +branch on top of the upstream head. Well, I lied. "git rebase" +is a bit smarter than that and notices that #2 and #3 need not +be applied, so it only applies #1. The commit ancestry graph +becomes something like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> where *your old "master" head +upstream --> #1 --> #2 --> #3 + used \ your new "master" head* + to be \--> #A --> #2' --> #3' --> #B --> #C --> #1' + *upstream + head</tt></pre> +</div></div> +<div class="paragraph"><p>Again, "git prune" would discard the disused commits #1-#3 and +you continue on starting from the new "master" head, which is +the #1' commit.</p></div> +<div class="paragraph"><p>-jc</p></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:08 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/rebase-from-internal-branch.txt b/howto/rebase-from-internal-branch.txt index 74a1c0c..4627ee4 100644 --- a/howto/rebase-from-internal-branch.txt +++ b/howto/rebase-from-internal-branch.txt
@@ -8,7 +8,12 @@ the "master" branch, and how "rebase" works. Also discussed is how this applies to individual developers who sends patches upstream. +Content-type: text/asciidoc +How to rebase from an internal branch +===================================== + +-------------------------------------- Petr Baudis <pasky@suse.cz> writes: > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter @@ -19,6 +24,7 @@ >> > branch to the real branches. >> > Actually, wouldn't this be also precisely for what StGIT is intended to? +-------------------------------------- Exactly my feeling. I was sort of waiting for Catalin to speak up. With its basing philosophical ancestry on quilt, this is @@ -156,8 +162,3 @@ the #1' commit. -jc - -- -To unsubscribe from this list: send the line "unsubscribe git" in -the body of a message to majordomo@vger.kernel.org -More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/howto/rebuild-from-update-hook.html b/howto/rebuild-from-update-hook.html new file mode 100644 index 0000000..13f020f --- /dev/null +++ b/howto/rebuild-from-update-hook.html
@@ -0,0 +1,670 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to rebuild from update hook</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to rebuild from update hook</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>The pages under <a href="http://www.kernel.org/pub/software/scm/git/docs/">http://www.kernel.org/pub/software/scm/git/docs/</a> +are built from Documentation/ directory of the git.git project +and needed to be kept up-to-date. The www.kernel.org/ servers +are mirrored and I was told that the origin of the mirror is on +the machine $some.kernel.org, on which I was given an account +when I took over git maintainership from Linus.</p></div> +<div class="paragraph"><p>The directories relevant to this how-to are these two:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>/pub/scm/git/git.git/ The public git repository. +/pub/software/scm/git/docs/ The HTML documentation page.</tt></pre> +</div></div> +<div class="paragraph"><p>So I made a repository to generate the documentation under my +home directory over there.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cd +$ mkdir doc-git && cd doc-git +$ git clone /pub/scm/git/git.git/ docgen</tt></pre> +</div></div> +<div class="paragraph"><p>What needs to happen is to update the $HOME/doc-git/docgen/ +working tree, build HTML docs there and install the result in +/pub/software/scm/git/docs/ directory. So I wrote a little +script:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cat >dododoc.sh <<\EOF +#!/bin/sh +cd $HOME/doc-git/docgen || exit</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>unset GIT_DIR</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git pull /pub/scm/git/git.git/ master && +cd Documentation && +make install-webdoc +EOF</tt></pre> +</div></div> +<div class="paragraph"><p>Initially I used to run this by hand whenever I push into the +public git repository. Then I did a cron job that ran twice a +day. The current round uses the post-update hook mechanism, +like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cat >/pub/scm/git/git.git/hooks/post-update <<\EOF +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, make this file executable by "chmod +x post-update".</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>case " $* " in +*' refs/heads/master '*) + echo $HOME/doc-git/dododoc.sh | at now + ;; +esac +exec git-update-server-info +EOF +$ chmod +x /pub/scm/git/git.git/hooks/post-update</tt></pre> +</div></div> +<div class="paragraph"><p>There are four things worth mentioning:</p></div> +<div class="ulist"><ul> +<li> +<p> +The update-hook is run after the repository accepts a "git + push", under my user privilege. It is given the full names + of refs that have been updated as arguments. My post-update + runs the dododoc.sh script only when the master head is + updated. +</p> +</li> +<li> +<p> +When update-hook is run, GIT_DIR is set to <em>.</em> by the calling + receive-pack. This is inherited by the dododoc.sh run via + the "at" command, and needs to be unset; otherwise, "git + pull" it does into $HOME/doc-git/docgen/ repository would not + work correctly. +</p> +</li> +<li> +<p> +The stdout of update hook script is not connected to git + push; I run the heavy part of the command inside "at", to + receive the execution report via e-mail. +</p> +</li> +<li> +<p> +This is still crude and does not protect against simultaneous + make invocations stomping on each other. I would need to add + some locking mechanism for this. +</p> +</li> +</ul></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:08 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/rebuild-from-update-hook.txt b/howto/rebuild-from-update-hook.txt index 48c6756..00c1b45 100644 --- a/howto/rebuild-from-update-hook.txt +++ b/howto/rebuild-from-update-hook.txt
@@ -5,6 +5,10 @@ Abstract: In this how-to article, JC talks about how he uses the post-update hook to automate git documentation page shown at http://www.kernel.org/pub/software/scm/git/docs/. +Content-type: text/asciidoc + +How to rebuild from update hook +=============================== The pages under http://www.kernel.org/pub/software/scm/git/docs/ are built from Documentation/ directory of the git.git project
diff --git a/howto/recover-corrupted-blob-object.html b/howto/recover-corrupted-blob-object.html new file mode 100644 index 0000000..3c6d516 --- /dev/null +++ b/howto/recover-corrupted-blob-object.html
@@ -0,0 +1,703 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to recover a corrupted blob object</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to recover a corrupted blob object</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="listingblock"> +<div class="content"> +<pre><tt>On Fri, 9 Nov 2007, Yossi Leybovich wrote: +> +> Did not help still the repository look for this object? +> Any one know how can I track this object and understand which file is it</tt></pre> +</div></div> +<div class="paragraph"><p>So exactly <strong>because</strong> the SHA1 hash is cryptographically secure, the hash +itself doesn’t actually tell you anything, in order to fix a corrupt +object you basically have to find the "original source" for it.</p></div> +<div class="paragraph"><p>The easiest way to do that is almost always to have backups, and find the +same object somewhere else. Backups really are a good idea, and git makes +it pretty easy (if nothing else, just clone the repository somewhere else, +and make sure that you do <strong>not</strong> use a hard-linked clone, and preferably +not the same disk/machine).</p></div> +<div class="paragraph"><p>But since you don’t seem to have backups right now, the good news is that +especially with a single blob being corrupt, these things <strong>are</strong> somewhat +debuggable.</p></div> +<div class="paragraph"><p>First off, move the corrupt object away, and <strong>save</strong> it. The most common +cause of corruption so far has been memory corruption, but even so, there +are people who would be interested in seeing the corruption - but it’s +basically impossible to judge the corruption until we can also see the +original object, so right now the corrupt object is useless, but it’s very +interesting for the future, in the hope that you can re-create a +non-corrupt version.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt>So: + +> ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../</tt></pre> +</div></div> +<div class="paragraph"><p>This is the right thing to do, although it’s usually best to save it under +it’s full SHA1 name (you just dropped the "4b" from the result ;).</p></div> +<div class="paragraph"><p>Let’s see what that tells us:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt>> ib]$ git-fsck --full +> broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 +> to blob 4b9458b3786228369c63936db65827de3cc06200 +> missing blob 4b9458b3786228369c63936db65827de3cc06200</tt></pre> +</div></div> +<div class="paragraph"><p>Ok, I removed the "dangling commit" messages, because they are just +messages about the fact that you probably have rebased etc, so they’re not +at all interesting. But what remains is still very useful. In particular, +we now know which tree points to it!</p></div> +<div class="paragraph"><p>Now you can do</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8</tt></pre> +</div></div> +<div class="paragraph"><p>which will show something like</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8 .gitignore +100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883 .mailmap +100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c COPYING +100644 blob ee909f2cc49e54f0799a4739d24c4cb9151ae453 CREDITS +040000 tree 0f5f709c17ad89e72bdbbef6ea221c69807009f6 Documentation +100644 blob 1570d248ad9237e4fa6e4d079336b9da62d9ba32 Kbuild +100644 blob 1c7c229a092665b11cd46a25dbd40feeb31661d9 MAINTAINERS +...</tt></pre> +</div></div> +<div class="paragraph"><p>and you should now have a line that looks like</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>10064 blob 4b9458b3786228369c63936db65827de3cc06200 my-magic-file</tt></pre> +</div></div> +<div class="paragraph"><p>in the output. This already tells you a <strong>lot</strong> it tells you what file the +corrupt blob came from!</p></div> +<div class="paragraph"><p>Now, it doesn’t tell you quite enough, though: it doesn’t tell what +<strong>version</strong> of the file didn’t get correctly written! You might be really +lucky, and it may be the version that you already have checked out in your +working tree, in which case fixing this problem is really simple, just do</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git hash-object -w my-magic-file</tt></pre> +</div></div> +<div class="paragraph"><p>again, and if it outputs the missing SHA1 (4b945..) you’re now all done!</p></div> +<div class="paragraph"><p>But that’s the really lucky case, so let’s assume that it was some older +version that was broken. How do you tell which version it was?</p></div> +<div class="paragraph"><p>The easiest way to do it is to do</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git log --raw --all --full-history -- subdirectory/my-magic-file</tt></pre> +</div></div> +<div class="paragraph"><p>and that will show you the whole log for that file (please realize that +the tree you had may not be the top-level tree, so you need to figure out +which subdirectory it was in on your own), and because you’re asking for +raw output, you’ll now get something like</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>commit abc +Author: +Date: + .. +:100644 100644 4b9458b... newsha... M somedirectory/my-magic-file</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>commit xyz +Author: +Date:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> .. +:100644 100644 oldsha... 4b9458b... M somedirectory/my-magic-file</tt></pre> +</div></div> +<div class="paragraph"><p>and this actually tells you what the <strong>previous</strong> and <strong>subsequent</strong> versions +of that file were! So now you can look at those ("oldsha" and "newsha" +respectively), and hopefully you have done commits often, and can +re-create the missing my-magic-file version by looking at those older and +newer versions!</p></div> +<div class="paragraph"><p>If you can do that, you can now recreate the missing object with</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git hash-object -w <recreated-file></tt></pre> +</div></div> +<div class="paragraph"><p>and your repository is good again!</p></div> +<div class="paragraph"><p>(Btw, you could have ignored the fsck, and started with doing a</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git log --raw --all</tt></pre> +</div></div> +<div class="paragraph"><p>and just looked for the sha of the missing object (4b9458b..) in that +whole thing. It’s up to you - git does <strong>have</strong> a lot of information, it is +just missing one particular blob version.</p></div> +<div class="paragraph"><p>Trying to recreate trees and especially commits is <strong>much</strong> harder. So you +were lucky that it’s a blob. It’s quite possible that you can recreate the +thing.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Linus</tt></pre> +</div></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:07 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/recover-corrupted-blob-object.txt b/howto/recover-corrupted-blob-object.txt index 323b513..7484735 100644 --- a/howto/recover-corrupted-blob-object.txt +++ b/howto/recover-corrupted-blob-object.txt
@@ -3,11 +3,17 @@ Subject: corrupt object on git-gc Abstract: Some tricks to reconstruct blob objects in order to fix a corrupted repository. +Content-type: text/asciidoc +How to recover a corrupted blob object +====================================== + +----------------------------------------------------------- On Fri, 9 Nov 2007, Yossi Leybovich wrote: > > Did not help still the repository look for this object? > Any one know how can I track this object and understand which file is it +----------------------------------------------------------- So exactly *because* the SHA1 hash is cryptographically secure, the hash itself doesn't actually tell you anything, in order to fix a corrupt @@ -31,19 +37,23 @@ interesting for the future, in the hope that you can re-create a non-corrupt version. +----------------------------------------------------------- So: > ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../ +----------------------------------------------------------- This is the right thing to do, although it's usually best to save it under it's full SHA1 name (you just dropped the "4b" from the result ;). Let's see what that tells us: +----------------------------------------------------------- > ib]$ git-fsck --full > broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 > to blob 4b9458b3786228369c63936db65827de3cc06200 > missing blob 4b9458b3786228369c63936db65827de3cc06200 +----------------------------------------------------------- Ok, I removed the "dangling commit" messages, because they are just messages about the fact that you probably have rebased etc, so they're not
diff --git a/howto/revert-a-faulty-merge.html b/howto/revert-a-faulty-merge.html new file mode 100644 index 0000000..0fe3c4f --- /dev/null +++ b/howto/revert-a-faulty-merge.html
@@ -0,0 +1,848 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to revert a faulty merge</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to revert a faulty merge</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>Alan <<a href="mailto:alan@clueserver.org">alan@clueserver.org</a>> said:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>I have a master branch. We have a branch off of that that some +developers are doing work on. They claim it is ready. We merge it +into the master branch. It breaks something so we revert the merge. +They make changes to the code. they get it to a point where they say +it is ok and we merge again.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>When examined, we find that code changes made before the revert are +not in the master branch, but code changes after are in the master +branch.</tt></pre> +</div></div> +<div class="paragraph"><p>and asked for help recovering from this situation.</p></div> +<div class="paragraph"><p>The history immediately after the "revert of the merge" would look like +this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W + / + ---A---B</tt></pre> +</div></div> +<div class="paragraph"><p>where A and B are on the side development that was not so good, M is the +merge that brings these premature changes into the mainline, x are changes +unrelated to what the side branch did and already made on the mainline, +and W is the "revert of the merge M" (doesn’t W look M upside down?). +IOW, "diff W<sup>..W" is similar to "diff -R M</sup>..M".</p></div> +<div class="paragraph"><p>Such a "revert" of a merge can be made with:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git revert -m 1 M</tt></pre> +</div></div> +<div class="paragraph"><p>After the developers of the side branch fix their mistakes, the history +may look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W---x + / + ---A---B-------------------C---D</tt></pre> +</div></div> +<div class="paragraph"><p>where C and D are to fix what was broken in A and B, and you may already +have some other changes on the mainline after W.</p></div> +<div class="paragraph"><p>If you merge the updated side branch (with D at its tip), none of the +changes made in A nor B will be in the result, because they were reverted +by W. That is what Alan saw.</p></div> +<div class="paragraph"><p>Linus explains the situation:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Reverting a regular commit just effectively undoes what that commit +did, and is fairly straightforward. But reverting a merge commit also +undoes the _data_ that the commit changed, but it does absolutely +nothing to the effects on _history_ that the merge had.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>So the merge will still exist, and it will still be seen as joining +the two branches together, and future merges will see that merge as +the last shared state - and the revert that reverted the merge brought +in will not affect that at all.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>So a "revert" undoes the data changes, but it's very much _not_ an +"undo" in the sense that it doesn't undo the effects of a commit on +the repository history.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>So if you think of "revert" as "undo", then you're going to always +miss this part of reverts. Yes, it undoes the data, but no, it doesn't +undo history.</tt></pre> +</div></div> +<div class="paragraph"><p>In such a situation, you would want to first revert the previous revert, +which would make the history look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W---x---Y + / + ---A---B-------------------C---D</tt></pre> +</div></div> +<div class="paragraph"><p>where Y is the revert of W. Such a "revert of the revert" can be done +with:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git revert W</tt></pre> +</div></div> +<div class="paragraph"><p>This history would (ignoring possible conflicts between what W and W..Y +changed) be equivalent to not having W nor Y at all in the history:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x-------x---- + / + ---A---B-------------------C---D</tt></pre> +</div></div> +<div class="paragraph"><p>and merging the side branch again will not have conflict arising from an +earlier revert and revert of the revert.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x-------x-------* + / / + ---A---B-------------------C---D</tt></pre> +</div></div> +<div class="paragraph"><p>Of course the changes made in C and D still can conflict with what was +done by any of the x, but that is just a normal merge conflict.</p></div> +<div class="paragraph"><p>On the other hand, if the developers of the side branch discarded their +faulty A and B, and redone the changes on top of the updated mainline +after the revert, the history would have looked like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W---x---x + / \ + ---A---B A'--B'--C'</tt></pre> +</div></div> +<div class="paragraph"><p>If you reverted the revert in such a case as in the previous example:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W---x---x---Y---* + / \ / + ---A---B A'--B'--C'</tt></pre> +</div></div> +<div class="paragraph"><p>where Y is the revert of W, A' and B' are rerolled A and B, and there may +also be a further fix-up C' on the side branch. "diff Y<sup>..Y" is similar +to "diff -R W</sup>..W" (which in turn means it is similar to "diff M<sup>..M"), +and "diff A'</sup>..C'" by definition would be similar but different from that, +because it is a rerolled series of the earlier change. There will be a +lot of overlapping changes that result in conflicts. So do not do "revert +of revert" blindly without thinking..</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>---o---o---o---M---x---x---W---x---x + / \ + ---A---B A'--B'--C'</tt></pre> +</div></div> +<div class="paragraph"><p>In the history with rebased side branch, W (and M) are behind the merge +base of the updated branch and the tip of the mainline, and they should +merge without the past faulty merge and its revert getting in the way.</p></div> +<div class="paragraph"><p>To recap, these are two very different scenarios, and they want two very +different resolution strategies:</p></div> +<div class="ulist"><ul> +<li> +<p> +If the faulty side branch was fixed by adding corrections on top, then + doing a revert of the previous revert would be the right thing to do. +</p> +</li> +<li> +<p> +If the faulty side branch whose effects were discarded by an earlier + revert of a merge was rebuilt from scratch (i.e. rebasing and fixing, + as you seem to have interpreted), then re-merging the result without + doing anything else fancy would be the right thing to do. + (See the ADDENDUM below for how to rebuild a branch from scratch + without changing its original branching-off point.) +</p> +</li> +</ul></div> +<div class="paragraph"><p>However, there are things to keep in mind when reverting a merge (and +reverting such a revert).</p></div> +<div class="paragraph"><p>For example, think about what reverting a merge (and then reverting the +revert) does to bisectability. Ignore the fact that the revert of a revert +is undoing it - just think of it as a "single commit that does a lot". +Because that is what it does.</p></div> +<div class="paragraph"><p>When you have a problem you are chasing down, and you hit a "revert this +merge", what you’re hitting is essentially a single commit that contains +all the changes (but obviously in reverse) of all the commits that got +merged. So it’s debugging hell, because now you don’t have lots of small +changes that you can try to pinpoint which <em>part</em> of it changes.</p></div> +<div class="paragraph"><p>But does it all work? Sure it does. You can revert a merge, and from a +purely technical angle, git did it very naturally and had no real +troubles. It just considered it a change from "state before merge" to +"state after merge", and that was it. Nothing complicated, nothing odd, +nothing really dangerous. Git will do it without even thinking about it.</p></div> +<div class="paragraph"><p>So from a technical angle, there’s nothing wrong with reverting a merge, +but from a workflow angle it’s something that you generally should try to +avoid.</p></div> +<div class="paragraph"><p>If at all possible, for example, if you find a problem that got merged +into the main tree, rather than revert the merge, try <em>really</em> hard to +bisect the problem down into the branch you merged, and just fix it, or +try to revert the individual commit that caused it.</p></div> +<div class="paragraph"><p>Yes, it’s more complex, and no, it’s not always going to work (sometimes +the answer is: "oops, I really shouldn’t have merged it, because it wasn’t +ready yet, and I really need to undo <em>all</em> of the merge"). So then you +really should revert the merge, but when you want to re-do the merge, you +now need to do it by reverting the revert.</p></div> +<div class="paragraph"><p>ADDENDUM</p></div> +<div class="paragraph"><p>Sometimes you have to rewrite one of a topic branch’s commits <strong>and</strong> you can’t +change the topic’s branching-off point. Consider the following situation:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>P---o---o---M---x---x---W---x + \ / + A---B---C</tt></pre> +</div></div> +<div class="paragraph"><p>where commit W reverted commit M because it turned out that commit B was wrong +and needs to be rewritten, but you need the rewritten topic to still branch +from commit P (perhaps P is a branching-off point for yet another branch, and +you want be able to merge the topic into both branches).</p></div> +<div class="paragraph"><p>The natural thing to do in this case is to checkout the A-B-C branch and use +"rebase -i P" to change commit B. However this does not rewrite commit A, +because "rebase -i" by default fast-forwards over any initial commits selected +with the "pick" command. So you end up with this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>P---o---o---M---x---x---W---x + \ / + A---B---C <-- old branch + \ + B'---C' <-- naively rewritten branch</tt></pre> +</div></div> +<div class="paragraph"><p>To merge A-B'-C' into the mainline branch you would still have to first revert +commit W in order to pick up the changes in A, but then it’s likely that the +changes in B' will conflict with the original B changes re-introduced by the +reversion of W.</p></div> +<div class="paragraph"><p>However, you can avoid these problems if you recreate the entire branch, +including commit A:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> A'---B'---C' <-- completely rewritten branch + / +P---o---o---M---x---x---W---x + \ / + A---B---C</tt></pre> +</div></div> +<div class="paragraph"><p>You can merge A'-B'-C' into the mainline branch without worrying about first +reverting W. Mainline’s history would look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> A'---B'---C'------------------ + / \ +P---o---o---M---x---x---W---x---M2 + \ / + A---B---C</tt></pre> +</div></div> +<div class="paragraph"><p>But if you don’t actually need to change commit A, then you need some way to +recreate it as a new commit with the same changes in it. The rebase command’s +--no-ff option provides a way to do this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git rebase [-i] --no-ff P</tt></pre> +</div></div> +<div class="paragraph"><p>The --no-ff option creates a new branch A'-B'-C' with all-new commits (all the +SHA IDs will be different) even if in the interactive case you only actually +modify commit B. You can then merge this new branch directly into the mainline +branch and be sure you’ll get all of the branch’s changes.</p></div> +<div class="paragraph"><p>You can also use --no-ff in cases where you just add extra commits to the topic +to fix it up. Let’s revisit the situation discussed at the start of this howto:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>P---o---o---M---x---x---W---x + \ / + A---B---C----------------D---E <-- fixed-up topic branch</tt></pre> +</div></div> +<div class="paragraph"><p>At this point, you can use --no-ff to recreate the topic branch:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git checkout E +$ git rebase --no-ff P</tt></pre> +</div></div> +<div class="paragraph"><p>yielding</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> A'---B'---C'------------D'---E' <-- recreated topic branch + / +P---o---o---M---x---x---W---x + \ / + A---B---C----------------D---E</tt></pre> +</div></div> +<div class="paragraph"><p>You can merge the recreated branch into the mainline without reverting commit W, +and mainline’s history will look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> A'---B'---C'------------D'---E' + / \ +P---o---o---M---x---x---W---x---M2 + \ / + A---B---C</tt></pre> +</div></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:07 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/revert-a-faulty-merge.txt b/howto/revert-a-faulty-merge.txt index 6fd7119..8a68548 100644 --- a/howto/revert-a-faulty-merge.txt +++ b/howto/revert-a-faulty-merge.txt
@@ -7,6 +7,10 @@ after the offending branch is fixed. Message-ID: <7vocz8a6zk.fsf@gitster.siamese.dyndns.org> References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain> +Content-type: text/asciidoc + +How to revert a faulty merge +============================ Alan <alan@clueserver.org> said:
diff --git a/howto/revert-branch-rebase.html b/howto/revert-branch-rebase.html index 5d3ab30..2cf1827 100644 --- a/howto/revert-branch-rebase.html +++ b/howto/revert-branch-rebase.html
@@ -4,7 +4,7 @@ <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="generator" content="AsciiDoc 8.5.2" /> -<title>Reverting an existing commit</title> +<title>How to revert an existing commit</title> <style type="text/css"> /* Debug borders */ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { @@ -551,7 +551,7 @@ </head> <body> <div id="header"> -<h1>Reverting an existing commit</h1> +<h1>How to revert an existing commit</h1> </div> <div id="content"> <div id="preamble"> @@ -723,7 +723,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2012-10-21 14:59:38 PDT +Last updated 2012-11-20 13:06:05 PDT </div> </div> </body>
diff --git a/howto/revert-branch-rebase.txt b/howto/revert-branch-rebase.txt index 093c656..a59ced8 100644 --- a/howto/revert-branch-rebase.txt +++ b/howto/revert-branch-rebase.txt
@@ -8,8 +8,8 @@ Content-type: text/asciidoc Message-ID: <7voe7g3uop.fsf@assigned-by-dhcp.cox.net> -Reverting an existing commit -============================ +How to revert an existing commit +================================ One of the changes I pulled into the 'master' branch turns out to break building GIT with GCC 2.95. While they were well intentioned
diff --git a/howto/separating-topic-branches.html b/howto/separating-topic-branches.html new file mode 100644 index 0000000..3120bdd --- /dev/null +++ b/howto/separating-topic-branches.html
@@ -0,0 +1,664 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to separate topic branches</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to separate topic branches</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>This text was originally a footnote to a discussion about the +behaviour of the git diff commands.</p></div> +<div class="paragraph"><p>Often I find myself doing that [running diff against something other +than HEAD] while rewriting messy development history. For example, I +start doing some work without knowing exactly where it leads, and end +up with a history like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> "master" +o---o + \ "topic" + o---o---o---o---o---o</tt></pre> +</div></div> +<div class="paragraph"><p>At this point, "topic" contains something I know I want, but it +contains two concepts that turned out to be completely independent. +And often, one topic component is larger than the other. It may +contain more than two topics.</p></div> +<div class="paragraph"><p>In order to rewrite this mess to be more manageable, I would first do +"diff master..topic", to extract the changes into a single patch, start +picking pieces from it to get logically self-contained units, and +start building on top of "master":</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git diff master..topic >P.diff +$ git checkout -b topicA master +... pick and apply pieces from P.diff to build +... commits on topicA branch.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> o---o---o + / "topicA" +o---o"master" + \ "topic" + o---o---o---o---o---o</tt></pre> +</div></div> +<div class="paragraph"><p>Before doing each commit on "topicA" HEAD, I run "diff HEAD" +before update-index the affected paths, or "diff --cached HEAD" +after. Also I would run "diff --cached master" to make sure +that the changes are only the ones related to "topicA". Usually +I do this for smaller topics first.</p></div> +<div class="paragraph"><p>After that, I’d do the remainder of the original "topic", but +for that, I do not start from the patchfile I extracted by +comparing "master" and "topic" I used initially. Still on +"topicA", I extract "diff topic", and use it to rebuild the +other topic:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git diff -R topic >P.diff ;# --cached also would work fine +$ git checkout -b topicB master +... pick and apply pieces from P.diff to build +... commits on topicB branch.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> "topicB" + o---o---o---o---o + / + /o---o---o + |/ "topicA" +o---o"master" + \ "topic" + o---o---o---o---o---o</tt></pre> +</div></div> +<div class="paragraph"><p>After I am done, I’d try a pretend-merge between "topicA" and +"topicB" in order to make sure I have not missed anything:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git pull . topicA ;# merge it into current "topicB" +$ git diff topic + "topicB" + o---o---o---o---o---* (pretend merge) + / / + /o---o---o----------' + |/ "topicA" +o---o"master" + \ "topic" + o---o---o---o---o---o</tt></pre> +</div></div> +<div class="paragraph"><p>The last diff better not to show anything other than cleanups +for crufts. Then I can finally clean things up:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git branch -D topic +$ git reset --hard HEAD^ ;# nuke pretend merge</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> "topicB" + o---o---o---o---o + / + /o---o---o + |/ "topicA" +o---o"master"</tt></pre> +</div></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:07 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/separating-topic-branches.txt b/howto/separating-topic-branches.txt index 6d3eb8e..bd10274 100644 --- a/howto/separating-topic-branches.txt +++ b/howto/separating-topic-branches.txt
@@ -1,6 +1,10 @@ From: Junio C Hamano <gitster@pobox.com> Subject: Separating topic branches Abstract: In this article, JC describes how to separate topic branches. +Content-type: text/asciidoc + +How to separate topic branches +============================== This text was originally a footnote to a discussion about the behaviour of the git diff commands.
diff --git a/howto/setup-git-server-over-http.html b/howto/setup-git-server-over-http.html new file mode 100644 index 0000000..f461101 --- /dev/null +++ b/howto/setup-git-server-over-http.html
@@ -0,0 +1,872 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to setup git server over http</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to setup git server over http</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>Since Apache is one of those packages people like to compile +themselves while others prefer the bureaucrat’s dream Debian, it is +impossible to give guidelines which will work for everyone. Just send +some feedback to the mailing list at <a href="mailto:git@vger.kernel.org">git@vger.kernel.org</a> to get this +document tailored to your favorite distro.</p></div> +<div class="paragraph"><p>What’s needed:</p></div> +<div class="ulist"><ul> +<li> +<p> +Have an Apache web-server +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: + $ apt-get install apache2 + To get apache2 by default started, + edit /etc/default/apache2 and set NO_START=0</tt></pre> +</div></div> +</li> +<li> +<p> +can edit the configuration of it. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>This could be found under /etc/httpd, or refer to your Apache documentation.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: this means being able to edit files under /etc/apache2</tt></pre> +</div></div> +</li> +<li> +<p> +can restart it. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>'apachectl --graceful' might do. If it doesn't, just stop and +restart apache. Be warning that active connections to your server +might be aborted by this.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: + $ /etc/init.d/apache2 restart +or + $ /etc/init.d/apache2 force-reload + (which seems to do the same) +This adds symlinks from the /etc/apache2/mods-enabled to +/etc/apache2/mods-available.</tt></pre> +</div></div> +</li> +<li> +<p> +have permissions to chown a directory +</p> +</li> +<li> +<p> +have git installed on the client, and +</p> +</li> +<li> +<p> +either have git installed on the server or have a webdav client on + the client. +</p> +</li> +</ul></div> +<div class="paragraph"><p>In effect, this means you’re going to be root, or that you’re using a +preconfigured WebDAV server.</p></div> +</div> +</div> +<h2 id="_step_1_setup_a_bare_git_repository">Step 1: setup a bare GIT repository</h2> +<div class="sectionbody"> +<div class="paragraph"><p>At the time of writing, git-http-push cannot remotely create a GIT +repository. So we have to do that at the server side with git. Another +option is to generate an empty bare repository at the client and copy +it to the server with a WebDAV client (which is the only option if Git +is not installed on the server).</p></div> +<div class="paragraph"><p>Create the directory under the DocumentRoot of the directories served +by Apache. As an example we take /usr/local/apache2, but try "grep +DocumentRoot /where/ever/httpd.conf" to find your root:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cd /usr/local/apache/htdocs +$ mkdir my-new-repo.git</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cd /var/www +$ mkdir my-new-repo.git</tt></pre> +</div></div> +<div class="paragraph"><p>Initialize a bare repository</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ cd my-new-repo.git +$ git --bare init</tt></pre> +</div></div> +<div class="paragraph"><p>Change the ownership to your web-server’s credentials. Use "grep <sup>User +httpd.conf" and "grep </sup>Group httpd.conf" to find out:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ chown -R www.www .</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ chown -R www-data.www-data .</tt></pre> +</div></div> +<div class="paragraph"><p>If you do not know which user Apache runs as, you can alternatively do +a "chmod -R a+w .", inspect the files which are created later on, and +set the permissions appropriately.</p></div> +<div class="paragraph"><p>Restart apache2, and check whether <a href="http://server/my-new-repo.git">http://server/my-new-repo.git</a> gives +a directory listing. If not, check whether apache started up +successfully.</p></div> +</div> +<h2 id="_step_2_enable_dav_on_this_repository">Step 2: enable DAV on this repository</h2> +<div class="sectionbody"> +<div class="paragraph"><p>First make sure the dav_module is loaded. For this, insert in httpd.conf:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>LoadModule dav_module libexec/httpd/libdav.so +AddModule mod_dav.c</tt></pre> +</div></div> +<div class="paragraph"><p>Also make sure that this line exists which is the file used for +locking DAV operations:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>DAVLockDB "/usr/local/apache2/temp/DAV.lock"</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian these steps can be performed with:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Enable the dav and dav_fs modules of apache: +$ a2enmod dav_fs +(just to be sure. dav_fs might be unneeded, I don't know) +$ a2enmod dav +The DAV lock is located in /etc/apache2/mods-available/dav_fs.conf: + DAVLockDB /var/lock/apache2/DAVLock</tt></pre> +</div></div> +<div class="paragraph"><p>Of course, it can point somewhere else, but the string is actually just a +prefix in some Apache configurations, and therefore the <em>directory</em> has to +be writable by the user Apache runs as.</p></div> +<div class="paragraph"><p>Then, add something like this to your httpd.conf</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><Location /my-new-repo.git> + DAV on + AuthType Basic + AuthName "Git" + AuthUserFile /usr/local/apache2/conf/passwd.git + Require valid-user +</Location></tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: + Create (or add to) /etc/apache2/conf.d/git.conf :</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><Location /my-new-repo.git> + DAV on + AuthType Basic + AuthName "Git" + AuthUserFile /etc/apache2/passwd.git + Require valid-user +</Location></tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Debian automatically reads all files under /etc/apache2/conf.d.</tt></pre> +</div></div> +<div class="paragraph"><p>The password file can be somewhere else, but it has to be readable by +Apache and preferably not readable by the world.</p></div> +<div class="paragraph"><p>Create this file by + $ htpasswd -c /usr/local/apache2/conf/passwd.git <user></p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: + $ htpasswd -c /etc/apache2/passwd.git <user></tt></pre> +</div></div> +<div class="paragraph"><p>You will be asked a password, and the file is created. Subsequent calls +to htpasswd should omit the <em>-c</em> option, since you want to append to the +existing file.</p></div> +<div class="paragraph"><p>You need to restart Apache.</p></div> +<div class="paragraph"><p>Now go to <a href="http://<username>@<servername>/my-new-repo.git">http://<username>@<servername>/my-new-repo.git</a> in your +browser to check whether it asks for a password and accepts the right +password.</p></div> +<div class="paragraph"><p>On Debian:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>To test the WebDAV part, do:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ apt-get install litmus +$ litmus http://<servername>/my-new-repo.git <username> <password></tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Most tests should pass.</tt></pre> +</div></div> +<div class="paragraph"><p>A command line tool to test WebDAV is cadaver. If you prefer GUIs, for +example, konqueror can open WebDAV URLs as "webdav://…" or +"webdavs://…".</p></div> +<div class="paragraph"><p>If you’re into Windows, from XP onwards Internet Explorer supports +WebDAV. For this, do Internet Explorer → Open Location → +<a href="http://<servername>/my-new-repo.git">http://<servername>/my-new-repo.git</a> [x] Open as webfolder → login .</p></div> +</div> +<h2 id="_step_3_setup_the_client">Step 3: setup the client</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Make sure that you have HTTP support, i.e. your git was built with +libcurl (version more recent than 7.10). The command <em>git http-push</em> with +no argument should display a usage message.</p></div> +<div class="paragraph"><p>Then, add the following to your $HOME/.netrc (you can do without, but will be +asked to input your password a <em>lot</em> of times):</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>machine <servername> +login <username> +password <password></tt></pre> +</div></div> +<div class="paragraph"><p>…and set permissions: + chmod 600 ~/.netrc</p></div> +<div class="paragraph"><p>If you want to access the web-server by its IP, you have to type that in, +instead of the server name.</p></div> +<div class="paragraph"><p>To check whether all is OK, do:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD</tt></pre> +</div></div> +<div class="paragraph"><p>…this should give something like <em>ref: refs/heads/master</em>, which is +the content of the file HEAD on the server.</p></div> +<div class="paragraph"><p>Now, add the remote in your existing repository which contains the project +you want to export:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git-config remote.upload.url \ + http://<username>@<servername>/my-new-repo.git/</tt></pre> +</div></div> +<div class="paragraph"><p>It is important to put the last <em>/</em>; Without it, the server will send +a redirect which git-http-push does not (yet) understand, and git-http-push +will repeat the request infinitely.</p></div> +</div> +<h2 id="_step_4_make_the_initial_push">Step 4: make the initial push</h2> +<div class="sectionbody"> +<div class="paragraph"><p>From your client repository, do</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git push upload master</tt></pre> +</div></div> +<div class="paragraph"><p>This pushes branch <em>master</em> (which is assumed to be the branch you +want to export) to repository called <em>upload</em>, which we previously +defined with git-config.</p></div> +</div> +<h2 id="_using_a_proxy">Using a proxy:</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If you have to access the WebDAV server from behind an HTTP(S) proxy, +set the variable <em>all_proxy</em> to <em>http://proxy-host.com:port</em>, or +<em>http://login-on-proxy:passwd-on-proxy@proxy-host.com:port</em>. See <em>man +curl</em> for details.</p></div> +</div> +<h2 id="_troubleshooting">Troubleshooting:</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If git-http-push says</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Error: no DAV locking support on remote repo http://...</tt></pre> +</div></div> +<div class="paragraph"><p>then it means the web-server did not accept your authentication. Make sure +that the user name and password matches in httpd.conf, .netrc and the URL +you are uploading to.</p></div> +<div class="paragraph"><p>If git-http-push shows you an error (22/502) when trying to MOVE a blob, +it means that your web-server somehow does not recognize its name in the +request; This can happen when you start Apache, but then disable the +network interface. A simple restart of Apache helps.</p></div> +<div class="paragraph"><p>Errors like (22/502) are of format (curl error code/http error +code). So (22/404) means something like <em>not found</em> at the server.</p></div> +<div class="paragraph"><p>Reading /usr/local/apache2/logs/error_log is often helpful.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>On Debian: Read /var/log/apache2/error.log instead.</tt></pre> +</div></div> +<div class="paragraph"><p>If you access HTTPS locations, git may fail verifying the SSL +certificate (this is return code 60). Setting http.sslVerify=false can +help diagnosing the problem, but removes security checks.</p></div> +<div class="paragraph"><p>Debian References: <a href="http://www.debian-administration.org/articles/285">http://www.debian-administration.org/articles/285</a></p></div> +<div class="paragraph"><p>Authors + Johannes Schindelin <<a href="mailto:Johannes.Schindelin@gmx.de">Johannes.Schindelin@gmx.de</a>> + Rutger Nijlunsing <<a href="mailto:git@wingding.demon.nl">git@wingding.demon.nl</a>> + Matthieu Moy <<a href="mailto:Matthieu.Moy@imag.fr">Matthieu.Moy@imag.fr</a>></p></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:06 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/setup-git-server-over-http.txt b/howto/setup-git-server-over-http.txt index 622ee5c..a695f01 100644 --- a/howto/setup-git-server-over-http.txt +++ b/howto/setup-git-server-over-http.txt
@@ -1,6 +1,10 @@ From: Rutger Nijlunsing <rutger@nospam.com> Subject: Setting up a git repository which can be pushed into and pulled from over HTTP(S). Date: Thu, 10 Aug 2006 22:00:26 +0200 +Content-type: text/asciidoc + +How to setup git server over http +================================= Since Apache is one of those packages people like to compile themselves while others prefer the bureaucrat's dream Debian, it is
diff --git a/howto/update-hook-example.html b/howto/update-hook-example.html new file mode 100644 index 0000000..2103990 --- /dev/null +++ b/howto/update-hook-example.html
@@ -0,0 +1,753 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to use the update hook</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to use the update hook</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>When your developer runs git-push into the repository, +git-receive-pack is run (either locally or over ssh) as that +developer, so is hooks/update script. Quoting from the relevant +section of the documentation:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Before each ref is updated, if $GIT_DIR/hooks/update file exists +and executable, it is called with three parameters:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$GIT_DIR/hooks/update refname sha1-old sha1-new</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The refname parameter is relative to $GIT_DIR; e.g. for the +master head this is "refs/heads/master". Two sha1 are the +object names for the refname before and after the update. Note +that the hook is called before the refname is updated, so either +sha1-old is 0{40} (meaning there is no such ref yet), or it +should match what is recorded in refname.</tt></pre> +</div></div> +<div class="paragraph"><p>So if your policy is (1) always require fast-forward push +(i.e. never allow "git-push repo +branch:branch"), (2) you +have a list of users allowed to update each branch, and (3) you +do not let tags to be overwritten, then you can use something +like this as your hooks/update script.</p></div> +<div class="paragraph"><p>[jc: editorial note. This is a much improved version by Carl +since I posted the original outline]</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt>#!/bin/bash + +umask 002 + +# If you are having trouble with this access control hook script +# you can try setting this to true. It will tell you exactly +# why a user is being allowed/denied access. + +verbose=false + +# Default shell globbing messes things up downstream +GLOBIGNORE=* + +function grant { + $verbose && echo >&2 "-Grant- $1" + echo grant + exit 0 +} + +function deny { + $verbose && echo >&2 "-Deny- $1" + echo deny + exit 1 +} + +function info { + $verbose && echo >&2 "-Info- $1" +} + +# Implement generic branch and tag policies. +# - Tags should not be updated once created. +# - Branches should only be fast-forwarded unless their pattern starts with '+' +case "$1" in + refs/tags/*) + git rev-parse --verify -q "$1" && + deny >/dev/null "You can't overwrite an existing tag" + ;; + refs/heads/*) + # No rebasing or rewinding + if expr "$2" : '0*$' >/dev/null; then + info "The branch '$1' is new..." + else + # updating -- make sure it is a fast-forward + mb=$(git-merge-base "$2" "$3") + case "$mb,$2" in + "$2,$mb") info "Update is fast-forward" ;; + *) noff=y; info "This is not a fast-forward update.";; + esac + fi + ;; + *) + deny >/dev/null \ + "Branch is not under refs/heads or refs/tags. What are you trying to do?" + ;; +esac + +# Implement per-branch controls based on username +allowed_users_file=$GIT_DIR/info/allowed-users +username=$(id -u -n) +info "The user is: '$username'" + +if test -f "$allowed_users_file" +then + rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' | + while read heads user_patterns + do + # does this rule apply to us? + head_pattern=${heads#+} + matchlen=$(expr "$1" : "${head_pattern#+}") + test "$matchlen" = ${#1} || continue + + # if non-ff, $heads must be with the '+' prefix + test -n "$noff" && + test "$head_pattern" = "$heads" && continue + + info "Found matching head pattern: '$head_pattern'" + for user_pattern in $user_patterns; do + info "Checking user: '$username' against pattern: '$user_pattern'" + matchlen=$(expr "$username" : "$user_pattern") + if test "$matchlen" = "${#username}" + then + grant "Allowing user: '$username' with pattern: '$user_pattern'" + fi + done + deny "The user is not in the access list for this branch" + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_users_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_users_file" ;; + *) ;; + esac +fi + +allowed_groups_file=$GIT_DIR/info/allowed-groups +groups=$(id -G -n) +info "The user belongs to the following groups:" +info "'$groups'" + +if test -f "$allowed_groups_file" +then + rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' | + while read heads group_patterns + do + # does this rule apply to us? + head_pattern=${heads#+} + matchlen=$(expr "$1" : "${head_pattern#+}") + test "$matchlen" = ${#1} || continue + + # if non-ff, $heads must be with the '+' prefix + test -n "$noff" && + test "$head_pattern" = "$heads" && continue + + info "Found matching head pattern: '$head_pattern'" + for group_pattern in $group_patterns; do + for groupname in $groups; do + info "Checking group: '$groupname' against pattern: '$group_pattern'" + matchlen=$(expr "$groupname" : "$group_pattern") + if test "$matchlen" = "${#groupname}" + then + grant "Allowing group: '$groupname' with pattern: '$group_pattern'" + fi + done + done + deny "None of the user's groups are in the access list for this branch" + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;; + *) ;; + esac +fi + +deny >/dev/null "There are no more rules to check. Denying access"</tt></pre> +</div></div> +<div class="paragraph"><p>This uses two files, $GIT_DIR/info/allowed-users and +allowed-groups, to describe which heads can be pushed into by +whom. The format of each file would look like this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>refs/heads/master junio ++refs/heads/pu junio +refs/heads/cogito$ pasky +refs/heads/bw/.* linus +refs/heads/tmp/.* .* +refs/tags/v[0-9].* junio</tt></pre> +</div></div> +<div class="paragraph"><p>With this, Linus can push or create "bw/penguin" or "bw/zebra" +or "bw/panda" branches, Pasky can do only "cogito", and JC can +do master and pu branches and make versioned tags. And anybody +can do tmp/blah branches. The <em>+</em> sign at the pu record means +that JC can make non-fast-forward pushes on it.</p></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:06 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/update-hook-example.txt b/howto/update-hook-example.txt index b7f8d41..a5193b1 100644 --- a/howto/update-hook-example.txt +++ b/howto/update-hook-example.txt
@@ -5,6 +5,10 @@ Abstract: An example hooks/update script is presented to implement repository maintenance policies, such as who can push into which branch and who can make a tag. +Content-type: text/asciidoc + +How to use the update hook +========================== When your developer runs git-push into the repository, git-receive-pack is run (either locally or over ssh) as that @@ -32,8 +36,7 @@ [jc: editorial note. This is a much improved version by Carl since I posted the original outline] --- >8 -- beginning of script -- >8 -- - +---------------------------------------------------- #!/bin/bash umask 002 @@ -111,12 +114,12 @@ info "Found matching head pattern: '$head_pattern'" for user_pattern in $user_patterns; do - info "Checking user: '$username' against pattern: '$user_pattern'" - matchlen=$(expr "$username" : "$user_pattern") - if test "$matchlen" = "${#username}" - then - grant "Allowing user: '$username' with pattern: '$user_pattern'" - fi + info "Checking user: '$username' against pattern: '$user_pattern'" + matchlen=$(expr "$username" : "$user_pattern") + if test "$matchlen" = "${#username}" + then + grant "Allowing user: '$username' with pattern: '$user_pattern'" + fi done deny "The user is not in the access list for this branch" done @@ -149,13 +152,13 @@ info "Found matching head pattern: '$head_pattern'" for group_pattern in $group_patterns; do - for groupname in $groups; do - info "Checking group: '$groupname' against pattern: '$group_pattern'" - matchlen=$(expr "$groupname" : "$group_pattern") - if test "$matchlen" = "${#groupname}" - then - grant "Allowing group: '$groupname' with pattern: '$group_pattern'" - fi + for groupname in $groups; do + info "Checking group: '$groupname' against pattern: '$group_pattern'" + matchlen=$(expr "$groupname" : "$group_pattern") + if test "$matchlen" = "${#groupname}" + then + grant "Allowing group: '$groupname' with pattern: '$group_pattern'" + fi done done deny "None of the user's groups are in the access list for this branch" @@ -169,24 +172,21 @@ fi deny >/dev/null "There are no more rules to check. Denying access" - --- >8 -- end of script -- >8 -- +---------------------------------------------------- This uses two files, $GIT_DIR/info/allowed-users and allowed-groups, to describe which heads can be pushed into by whom. The format of each file would look like this: - refs/heads/master junio - +refs/heads/pu junio - refs/heads/cogito$ pasky - refs/heads/bw/.* linus - refs/heads/tmp/.* .* - refs/tags/v[0-9].* junio + refs/heads/master junio + +refs/heads/pu junio + refs/heads/cogito$ pasky + refs/heads/bw/.* linus + refs/heads/tmp/.* .* + refs/tags/v[0-9].* junio With this, Linus can push or create "bw/penguin" or "bw/zebra" or "bw/panda" branches, Pasky can do only "cogito", and JC can do master and pu branches and make versioned tags. And anybody can do tmp/blah branches. The '+' sign at the pu record means that JC can make non-fast-forward pushes on it. - -------------
diff --git a/howto/use-git-daemon.html b/howto/use-git-daemon.html new file mode 100644 index 0000000..366c868 --- /dev/null +++ b/howto/use-git-daemon.html
@@ -0,0 +1,614 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>How to use git-daemon</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>How to use git-daemon</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>Git can be run in inetd mode and in stand alone mode. But all you want is +let a coworker pull from you, and therefore need to set up a git server +real quick, right?</p></div> +<div class="paragraph"><p>Note that git-daemon is not really chatty at the moment, especially when +things do not go according to plan (e.g. a socket could not be bound).</p></div> +<div class="paragraph"><p>Another word of warning: if you run</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git ls-remote git://127.0.0.1/rule-the-world.git</tt></pre> +</div></div> +<div class="paragraph"><p>and you see a message like</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>fatal: The remote end hung up unexpectedly</tt></pre> +</div></div> +<div class="paragraph"><p>it only means that <em>something</em> went wrong. To find out <em>what</em> went wrong, +you have to ask the server. (Git refuses to be more precise for your +security only. Take off your shoes now. You have any coins in your pockets? +Sorry, not allowed — who knows what you planned to do with them?)</p></div> +<div class="paragraph"><p>With these two caveats, let’s see an example:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git daemon --reuseaddr --verbose --base-path=/home/gitte/git \ + --export-all -- /home/gitte/git/rule-the-world.git</tt></pre> +</div></div> +<div class="paragraph"><p>(Of course, unless your user name is <tt>gitte</tt> <em>and</em> your repository is in +~/rule-the-world.git, you have to adjust the paths. If your repository is +not bare, be aware that you have to type the path to the .git directory!)</p></div> +<div class="paragraph"><p>This invocation tries to reuse the address if it is already taken +(this can save you some debugging, because otherwise killing and restarting +git-daemon could just silently fail to bind to a socket).</p></div> +<div class="paragraph"><p>Also, it is (relatively) verbose when somebody actually connects to it. +It also sets the base path, which means that all the projects which can be +accessed using this daemon have to reside in or under that path.</p></div> +<div class="paragraph"><p>The option <tt>--export-all</tt> just means that you <em>don’t</em> have to create a +file named <tt>git-daemon-export-ok</tt> in each exported repository. (Otherwise, +git-daemon would complain loudly, and refuse to cooperate.)</p></div> +<div class="paragraph"><p>Last of all, the repository which should be exported is specified. It is +a good practice to put the paths after a "--" separator.</p></div> +<div class="paragraph"><p>Now, test your daemon with</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git ls-remote git://127.0.0.1/rule-the-world.git</tt></pre> +</div></div> +<div class="paragraph"><p>If this does not work, find out why, and submit a patch to this document.</p></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:06 PDT +</div> +</div> +</body> +</html>
diff --git a/howto/use-git-daemon.txt b/howto/use-git-daemon.txt index 4e2f75c..23cdf35 100644 --- a/howto/use-git-daemon.txt +++ b/howto/use-git-daemon.txt
@@ -1,4 +1,7 @@ +Content-type: text/asciidoc + How to use git-daemon +===================== Git can be run in inetd mode and in stand alone mode. But all you want is let a coworker pull from you, and therefore need to set up a git server
diff --git a/howto/using-signed-tag-in-pull-request.html b/howto/using-signed-tag-in-pull-request.html index 0ccdb7d..a4d3793 100644 --- a/howto/using-signed-tag-in-pull-request.html +++ b/howto/using-signed-tag-in-pull-request.html
@@ -4,7 +4,7 @@ <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta name="generator" content="AsciiDoc 8.5.2" /> -<title>Using signed tag in pull requests</title> +<title>How to use a signed tag in pull requests</title> <style type="text/css"> /* Debug borders */ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { @@ -551,7 +551,7 @@ </head> <body> <div id="header"> -<h1>Using signed tag in pull requests</h1> +<h1>How to use a signed tag in pull requests</h1> </div> <div id="content"> <div id="preamble"> @@ -762,7 +762,7 @@ <div id="footnotes"><hr /></div> <div id="footer"> <div id="footer-text"> -Last updated 2012-10-21 14:59:39 PDT +Last updated 2012-11-20 13:06:05 PDT </div> </div> </body>
diff --git a/howto/using-signed-tag-in-pull-request.txt b/howto/using-signed-tag-in-pull-request.txt index 98c0033..00f693b 100644 --- a/howto/using-signed-tag-in-pull-request.txt +++ b/howto/using-signed-tag-in-pull-request.txt
@@ -7,8 +7,8 @@ later validate it. Content-type: text/asciidoc -Using signed tag in pull requests -================================= +How to use a signed tag in pull requests +======================================== A typical distributed workflow using Git is for a contributor to fork a project, build on it, publish the result to her public repository, and ask
diff --git a/technical/index-format.html b/technical/index-format.html new file mode 100644 index 0000000..369fdde --- /dev/null +++ b/technical/index-format.html
@@ -0,0 +1,905 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>GIT index format</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>GIT index format</h1> +</div> +<div id="content"> +<h2 id="_the_git_index_file_has_the_following_format">The git index file has the following format</h2> +<div class="sectionbody"> +<div class="literalblock"> +<div class="content"> +<pre><tt>All binary numbers are in network byte order. Version 2 is described +here unless stated otherwise.</tt></pre> +</div></div> +<div class="ulist"><ul> +<li> +<p> +A 12-byte header consisting of +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte signature: + The signature is { 'D', 'I', 'R', 'C' } (stands for "dircache")</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte version number: + The current supported versions are 2 and 3.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit number of index entries.</tt></pre> +</div></div> +</li> +<li> +<p> +A number of sorted index entries (see below). +</p> +</li> +<li> +<p> +Extensions +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>Extensions are identified by signature. Optional extensions can +be ignored if GIT does not understand them.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>GIT currently supports cached tree and resolve undo extensions.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte extension signature. If the first byte is 'A'..'Z' the +extension is optional and can be ignored.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit size of the extension</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Extension data</tt></pre> +</div></div> +</li> +<li> +<p> +160-bit SHA-1 over the content of the index file before this + checksum. +</p> +</li> +</ul></div> +</div> +<h2 id="_index_entry">Index entry</h2> +<div class="sectionbody"> +<div class="literalblock"> +<div class="content"> +<pre><tt>Index entries are sorted in ascending order on the name field, +interpreted as a string of unsigned bytes (i.e. memcmp() order, no +localization, no special casing of directory separator '/'). Entries +with the same name are sorted by their stage field.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit ctime seconds, the last time a file's metadata changed + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit ctime nanosecond fractions + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit mtime seconds, the last time a file's data changed + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit mtime nanosecond fractions + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit dev + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit ino + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit mode, split into (high to low bits)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-bit object type + valid values in binary are 1000 (regular file), 1010 (symbolic link) + and 1110 (gitlink)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>3-bit unused</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>9-bit unix permission. Only 0755 and 0644 are valid for regular files. +Symbolic links and gitlinks have value 0 in this field.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit uid + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit gid + this is stat(2) data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>32-bit file size + This is the on-disk size from stat(2), truncated to 32-bit.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>160-bit SHA-1 for the represented object</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>A 16-bit 'flags' field split into (high to low bits)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-bit assume-valid flag</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-bit extended flag (must be zero in version 2)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>2-bit stage (during merge)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>12-bit name length if the length is less than 0xFFF; otherwise 0xFFF +is stored in this field.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(Version 3) A 16-bit field, only applicable if the "extended flag" +above is 1, split into (high to low bits).</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-bit reserved for future</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-bit skip-worktree flag (used by sparse checkout)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-bit intent-to-add flag (used by "git add -N")</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>13-bit unused, must be zero</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Entry path name (variable length) relative to top level directory + (without leading slash). '/' is used as path separator. The special + path components ".", ".." and ".git" (without quotes) are disallowed. + Trailing slash is also disallowed.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The exact encoding is undefined, but the '.' and '/' characters +are encoded in 7-bit ASCII and the encoding cannot contain a NUL +byte (iow, this is a UNIX pathname).</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(Version 4) In version 4, the entry path name is prefix-compressed + relative to the path name for the previous entry (the very first + entry is encoded as if the path name for the previous entry is an + empty string). At the beginning of an entry, an integer N in the + variable width encoding (the same encoding as the offset is encoded + for OFS_DELTA pack entries; see pack-format.txt) is stored, followed + by a NUL-terminated string S. Removing N bytes from the end of the + path name for the previous entry, and replacing it with the string S + yields the path name for this entry.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes +while keeping the name NUL-terminated.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(Version 4) In version 4, the padding after the pathname does not +exist.</tt></pre> +</div></div> +</div> +<h2 id="_extensions">Extensions</h2> +<div class="sectionbody"> +<h3 id="_cached_tree">Cached tree</h3><div style="clear:left"></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Cached tree extension contains pre-computed hashes for trees that can +be derived from the index. It helps speed up tree object generation +from index for a new commit.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>When a path is updated in index, the path must be invalidated and +removed from tree cache.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The signature for this extension is { 'T', 'R', 'E', 'E' }.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>A series of entries fill the entire extension; each of which +consists of:</tt></pre> +</div></div> +<div class="ulist"><ul> +<li> +<p> +NUL-terminated path component (relative to its parent directory); +</p> +</li> +<li> +<p> +ASCII decimal number of entries in the index that is covered by the + tree this entry represents (entry_count); +</p> +</li> +<li> +<p> +A space (ASCII 32); +</p> +</li> +<li> +<p> +ASCII decimal number that represents the number of subtrees this + tree has; +</p> +</li> +<li> +<p> +A newline (ASCII 10); and +</p> +</li> +<li> +<p> +160-bit object name for the object that would result from writing + this span of index as a tree. +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>An entry can be in an invalidated state and is represented by having +-1 in the entry_count field. In this case, there is no object name +and the next entry starts immediately after the newline.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The entries are written out in the top-down, depth-first order. The +first entry represents the root level of the repository, followed by the +first subtree---let's call this A---of the root level (with its name +relative to the root level), followed by the first subtree of A (with +its name relative to A), ...</tt></pre> +</div></div> +</li> +</ul></div> +<h3 id="_resolve_undo">Resolve undo</h3><div style="clear:left"></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>A conflict is represented in the index as a set of higher stage entries. +When a conflict is resolved (e.g. with "git add path"), these higher +stage entries will be removed and a stage-0 entry with proper resoluton +is added.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>When these higher stage entries are removed, they are saved in the +resolve undo extension, so that conflicts can be recreated (e.g. with +"git checkout -m"), in case users want to redo a conflict resolution +from scratch.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The signature for this extension is { 'R', 'E', 'U', 'C' }.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>A series of entries fill the entire extension; each of which +consists of:</tt></pre> +</div></div> +<div class="ulist"><ul> +<li> +<p> +NUL-terminated pathname the entry describes (relative to the root of + the repository, i.e. full pathname); +</p> +</li> +<li> +<p> +Three NUL-terminated ASCII octal numbers, entry mode of entries in + stage 1 to 3 (a missing stage is represented by "0" in this field); + and +</p> +</li> +<li> +<p> +At most three 160-bit object names of the entry in stages from 1 to 3 + (nothing is written for a missing stage). +</p> +</li> +</ul></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/index-format.txt b/technical/index-format.txt index 9d25b30..57d6f91 100644 --- a/technical/index-format.txt +++ b/technical/index-format.txt
@@ -1,7 +1,7 @@ GIT index format ================ -= The git index file has the following format +== The git index file has the following format All binary numbers are in network byte order. Version 2 is described here unless stated otherwise.
diff --git a/technical/pack-format.html b/technical/pack-format.html new file mode 100644 index 0000000..0a99703 --- /dev/null +++ b/technical/pack-format.html
@@ -0,0 +1,806 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>GIT pack format</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>GIT pack format</h1> +</div> +<div id="content"> +<h2 id="_pack_pack_files_have_the_following_format">pack-*.pack files have the following format:</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +A header appears at the beginning and consists of the following: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte signature: + The signature is: {'P', 'A', 'C', 'K'}</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte version number (network byte order): + GIT currently accepts version number 2 or 3 but + generates version 2 only.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte number of objects contained in the pack (network byte order)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Observation: we cannot have more than 4G versions ;-) and +more than 4G objects in a pack.</tt></pre> +</div></div> +</li> +<li> +<p> +The header is followed by number of object entries, each of + which looks like this: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>(undeltified representation) +n-byte type and length (3-bit type, (n-1)*7+4-bit length) +compressed data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(deltified representation) +n-byte type and length (3-bit type, (n-1)*7+4-bit length) +20-byte base object name +compressed delta data</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Observation: length of each object is encoded in a variable +length format and is not constrained to 32-bit or anything.</tt></pre> +</div></div> +</li> +<li> +<p> +The trailer records 20-byte SHA1 checksum of all of the above. +</p> +</li> +</ul></div> +</div> +<h2 id="_original_version_1_pack_idx_files_have_the_following_format">Original (version 1) pack-*.idx files have the following format:</h2> +<div class="sectionbody"> +<div class="ulist"><ul> +<li> +<p> +The header consists of 256 4-byte network byte order + integers. N-th entry of this table records the number of + objects in the corresponding pack, the first byte of whose + object name is less than or equal to N. This is called the + <em>first-level fan-out</em> table. +</p> +</li> +<li> +<p> +The header is followed by sorted 24-byte entries, one entry + per object in the pack. Each entry is: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>4-byte network byte order integer, recording where the +object is stored in the packfile as the offset from the +beginning.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>20-byte object name.</tt></pre> +</div></div> +</li> +<li> +<p> +The file is concluded with a trailer: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>A copy of the 20-byte SHA1 checksum at the end of +corresponding packfile.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>20-byte SHA1-checksum of all of the above.</tt></pre> +</div></div> +</li> +</ul></div> +<div class="paragraph"><p>Pack Idx file:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> -- +--------------------------------+ +fanout | fanout[0] = 2 (for example) |-. +table +--------------------------------+ | + | fanout[1] | | + +--------------------------------+ | + | fanout[2] | | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | + | fanout[255] = total objects |---. + -- +--------------------------------+ | | +main | offset | | | +index | object name 00XXXXXXXXXXXXXXXX | | | +table +--------------------------------+ | | + | offset | | | + | object name 00XXXXXXXXXXXXXXXX | | | + +--------------------------------+<+ | + .-| offset | | + | | object name 01XXXXXXXXXXXXXXXX | | + | +--------------------------------+ | + | | offset | | + | | object name 01XXXXXXXXXXXXXXXX | | + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | + | | offset | | + | | object name FFXXXXXXXXXXXXXXXX | | + --| +--------------------------------+<--+ +trailer | | packfile checksum | + | +--------------------------------+ + | | idxfile checksum | + | +--------------------------------+ + .-------. + | +Pack file entry: <+</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>packed object header: + 1-byte size extension bit (MSB) + type (next 3 bit) + size0 (lower 4-bit) + n-byte sizeN (as long as MSB is set, each 7-bit) + size0..sizeN form 4+7+7+..+7 bit integer, size0 + is the least significant part, and sizeN is the + most significant part. +packed object data: + If it is not DELTA, then deflated bytes (the size above + is the size before compression). + If it is REF_DELTA, then + 20-byte base object name SHA1 (the size above is the + size of the delta data that follows). + delta data, deflated. + If it is OFS_DELTA, then + n-byte offset (see below) interpreted as a negative + offset from the type-byte of the header of the + ofs-delta entry (the size above is the size of + the delta data that follows). + delta data, deflated.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>offset encoding: + n bytes with MSB set in all but the last one. + The offset is then the number constructed by + concatenating the lower 7 bit of each byte, and + for n >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1)) + to the result.</tt></pre> +</div></div> +</div> +<h2 id="_version_2_pack_idx_files_support_packs_larger_than_4_gib_and">Version 2 pack-*.idx files support packs larger than 4 GiB, and</h2> +<div class="sectionbody"> +<div class="literalblock"> +<div class="content"> +<pre><tt>have some other reorganizations. They have the format:</tt></pre> +</div></div> +<div class="ulist"><ul> +<li> +<p> +A 4-byte magic number <em>\377tOc</em> which is an unreasonable + fanout[0] value. +</p> +</li> +<li> +<p> +A 4-byte version number (= 2) +</p> +</li> +<li> +<p> +A 256-entry fan-out table just like v1. +</p> +</li> +<li> +<p> +A table of sorted 20-byte SHA1 object names. These are + packed together without offset values to reduce the cache + footprint of the binary search for a specific object name. +</p> +</li> +<li> +<p> +A table of 4-byte CRC32 values of the packed object data. + This is new in v2 so compressed data can be copied directly + from pack to pack during repacking without undetected + data corruption. +</p> +</li> +<li> +<p> +A table of 4-byte offset values (in network byte order). + These are usually 31-bit pack file offsets, but large + offsets are encoded as an index into the next table with + the msbit set. +</p> +</li> +<li> +<p> +A table of 8-byte offset entries (empty for pack files less + than 2 GiB). Pack files are organized with heavily used + objects toward the front, so most object references should + not need to refer to this table. +</p> +</li> +<li> +<p> +The same trailer as a v1 pack file: +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt>A copy of the 20-byte SHA1 checksum at the end of +corresponding packfile.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>20-byte SHA1-checksum of all of the above.</tt></pre> +</div></div> +</li> +</ul></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/pack-format.txt b/technical/pack-format.txt index 1803e64..a7871fb 100644 --- a/technical/pack-format.txt +++ b/technical/pack-format.txt
@@ -1,7 +1,7 @@ GIT pack format =============== -= pack-*.pack files have the following format: +== pack-*.pack files have the following format: - A header appears at the beginning and consists of the following: @@ -34,7 +34,7 @@ - The trailer records 20-byte SHA1 checksum of all of the above. -= Original (version 1) pack-*.idx files have the following format: +== Original (version 1) pack-*.idx files have the following format: - The header consists of 256 4-byte network byte order integers. N-th entry of this table records the number of @@ -123,8 +123,8 @@ -= Version 2 pack-*.idx files support packs larger than 4 GiB, and - have some other reorganizations. They have the format: +== Version 2 pack-*.idx files support packs larger than 4 GiB, and + have some other reorganizations. They have the format: - A 4-byte magic number '\377tOc' which is an unreasonable fanout[0] value.
diff --git a/technical/pack-heuristics.html b/technical/pack-heuristics.html new file mode 100644 index 0000000..a8ea7c9 --- /dev/null +++ b/technical/pack-heuristics.html
@@ -0,0 +1,1172 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title></title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +</div> +<div id="content"> +<div class="literalblock"> +<div class="content"> +<pre><tt>Concerning Git's Packing Heuristics +===================================</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Oh, here's a really stupid question:</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> Where do I go + to learn the details +of git's packing heuristics?</tt></pre> +</div></div> +<div class="paragraph"><p>Be careful what you ask!</p></div> +<div class="paragraph"><p>Followers of the git, please open the git IRC Log and turn to +February 10, 2006.</p></div> +<div class="paragraph"><p>It’s a rare occasion, and we are joined by the King Git Himself, +Linus Torvalds (linus). Nathaniel Smith, (njs`), has the floor +and seeks enlightenment. Others are present, but silent.</p></div> +<div class="paragraph"><p>Let’s listen in!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Oh, here's a really stupid question -- where do I go to + learn the details of git's packing heuristics? google avails + me not, reading the source didn't help a lot, and wading + through the whole mailing list seems less efficient than any + of that.</tt></pre> +</div></div> +<div class="paragraph"><p>It is a bold start! A plea for help combined with a simultaneous +tri-part attack on some of the tried and true mainstays in the quest +for enlightenment. Brash accusations of google being useless. Hubris! +Maligning the source. Heresy! Disdain for the mailing list archives. +Woe.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> yes, the packing-related delta stuff is somewhat + mysterious even for me ;)</tt></pre> +</div></div> +<div class="paragraph"><p>Ah! Modesty after all.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> njs, I don't think the docs exist. That's something where + I don't think anybody else than me even really got involved. + Most of the rest of git others have been busy with (especially + Junio), but packing nobody touched after I did it.</tt></pre> +</div></div> +<div class="paragraph"><p>It’s cryptic, yet vague. Linus in style for sure. Wise men +interpret this as an apology. A few argue it is merely a +statement of fact.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> I guess the next step is "read the source again", but I + have to build up a certain level of gumption first :-)</tt></pre> +</div></div> +<div class="paragraph"><p>Indeed! On both points.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> The packing heuristic is actually really really simple.</tt></pre> +</div></div> +<div class="paragraph"><p>Bait…</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> But strange.</tt></pre> +</div></div> +<div class="paragraph"><p>And switch. That ought to do it!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Remember: git really doesn't follow files. So what it does is + - generate a list of all objects + - sort the list according to magic heuristics + - walk the list, using a sliding window, seeing if an object + can be diffed against another object in the window + - write out the list in recency order</tt></pre> +</div></div> +<div class="paragraph"><p>The traditional understatement:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> I suspect that what I'm missing is the precise definition of + the word "magic"</tt></pre> +</div></div> +<div class="paragraph"><p>The traditional insight:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> yes</tt></pre> +</div></div> +<div class="paragraph"><p>And Babel-like confusion flowed.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> oh, hmm, and I'm not sure what this sliding window means either</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> iirc, it appeared to me to be just the sha1 of the object + when reading the code casually ...</tt></pre> +</div></div> +<div class="olist lowerroman"><ol class="lowerroman"> +<li> +<p> +which simply doesn’t sound as a very good heuristics, though ;) +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> .....and recency order. okay, I think it's clear I didn't + even realize how much I wasn't realizing :-)</tt></pre> +</div></div> +</li> +</ol></div> +<div class="paragraph"><p>Ah, grasshopper! And thus the enlightenment begins anew.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> The "magic" is actually in theory totally arbitrary. + ANY order will give you a working pack, but no, it's not + ordered by SHA1.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Before talking about the ordering for the sliding delta +window, let's talk about the recency order. That's more +important in one way.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Right, but if all you want is a working way to pack things + together, you could just use cat and save yourself some + trouble...</tt></pre> +</div></div> +<div class="paragraph"><p>Waaait for it….</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> The recency ordering (which is basically: put objects + _physically_ into the pack in the order that they are + "reachable" from the head) is important.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> okay</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> It's important because that's the thing that gives packs + good locality. It keeps the objects close to the head (whether + they are old or new, but they are _reachable_ from the head) + at the head of the pack. So packs actually have absolutely + _wonderful_ IO patterns.</tt></pre> +</div></div> +<div class="paragraph"><p>Read that again, because it is important.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> But recency ordering is totally useless for deciding how + to actually generate the deltas, so the delta ordering is + something else.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The delta ordering is (wait for it): +- first sort by the "basename" of the object, as defined by + the name the object was _first_ reached through when + generating the object list +- within the same basename, sort by size of the object +- but always sort different types separately (commits first).</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>That's not exactly it, but it's very close.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> The "_first_ reached" thing is not too important, just you + need some way to break ties since the same objects may be + reachable many ways, yes?</tt></pre> +</div></div> +<div class="paragraph"><p>And as if to clarify:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> The point is that it's all really just any random + heuristic, and the ordering is totally unimportant for + correctness, but it helps a lot if the heuristic gives + "clumping" for things that are likely to delta well against + each other.</tt></pre> +</div></div> +<div class="paragraph"><p>It is an important point, so secretly, I did my own research and have +included my results below. To be fair, it has changed some over time. +And through the magic of Revisionistic History, I draw upon this entry +from The Git IRC Logs on my father’s birthday, March 1:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><gitster> The quote from the above linus should be rewritten a + bit (wait for it): + - first sort by type. Different objects never delta with + each other. + - then sort by filename/dirname. hash of the basename + occupies the top BITS_PER_INT-DIR_BITS bits, and bottom + DIR_BITS are for the hash of leading path elements. + - then if we are doing "thin" pack, the objects we are _not_ + going to pack but we know about are sorted earlier than + other objects. + - and finally sort by size, larger to smaller.</tt></pre> +</div></div> +<div class="paragraph"><p>In one swell-foop, clarification and obscurification! Nonetheless, +authoritative. Cryptic, yet concise. It even solicits notions of +quotes from The Source Code. Clearly, more study is needed.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><gitster> That's the sort order. What this means is: + - we do not delta different object types. + - we prefer to delta the objects with the same full path, but + allow files with the same name from different directories. + - we always prefer to delta against objects we are not going + to send, if there are some. + - we prefer to delta against larger objects, so that we have + lots of removals.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>The penultimate rule is for "thin" packs. It is used when +the other side is known to have such objects.</tt></pre> +</div></div> +<div class="paragraph"><p>There it is again. "Thin" packs. I’m thinking to myself, "What +is a <em>thin</em> pack?" So I ask:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><jdl> What is a "thin" pack?</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><gitster> Use of --objects-edge to rev-list as the upstream of + pack-objects. The pack transfer protocol negotiates that.</tt></pre> +</div></div> +<div class="paragraph"><p>Woo hoo! Cleared that <em>right</em> up!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><gitster> There are two directions - push and fetch.</tt></pre> +</div></div> +<div class="paragraph"><p>There! Did you see it? It is not <em>"push" and "pull"</em>! How often the +confusion has started here. So casually mentioned, too!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><gitster> For push, git-send-pack invokes git-receive-pack on the + other end. The receive-pack says "I have up to these commits". + send-pack looks at them, and computes what are missing from + the other end. So "thin" could be the default there.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>In the other direction, fetch, git-fetch-pack and +git-clone-pack invokes git-upload-pack on the other end +(via ssh or by talking to the daemon).</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>There are two cases: fetch-pack with -k and clone-pack is one, +fetch-pack without -k is the other. clone-pack and fetch-pack +with -k will keep the downloaded packfile without expanded, so +we do not use thin pack transfer. Otherwise, the generated +pack will have delta without base object in the same pack.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>But fetch-pack without -k will explode the received pack into +individual objects, so we automatically ask upload-pack to +give us a thin pack if upload-pack supports it.</tt></pre> +</div></div> +<div class="paragraph"><p>OK then.</p></div> +<div class="paragraph"><p>Uh.</p></div> +<div class="paragraph"><p>Let’s return to the previous conversation still in progress.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> and "basename" means something like "the tail of end of + path of file objects and dir objects, as per basename(3), and + we just declare all commit and tag objects to have the same + basename" or something?</tt></pre> +</div></div> +<div class="paragraph"><p>Luckily, that too is a point that gitster clarified for us!</p></div> +<div class="paragraph"><p>If I might add, the trick is to make files that <em>might</em> be similar be +located close to each other in the hash buckets based on their file +names. It used to be that "foo/Makefile", "bar/baz/quux/Makefile" and +"Makefile" all landed in the same bucket due to their common basename, +"Makefile". However, now they land in "close" buckets.</p></div> +<div class="paragraph"><p>The algorithm allows not just for the <em>same</em> bucket, but for <em>close</em> +buckets to be considered delta candidates. The rationale is +essentially that files, like Makefiles, often have very similar +content no matter what directory they live in.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> I played around with different delta algorithms, and with + making the "delta window" bigger, but having too big of a + sliding window makes it very expensive to generate the pack: + you need to compare every object with a _ton_ of other objects.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>There are a number of other trivial heuristics too, which +basically boil down to "don't bother even trying to delta this +pair" if we can tell before-hand that the delta isn't worth it +(due to size differences, where we can take a previous delta +result into account to decide that "ok, no point in trying +that one, it will be worse").</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>End result: packing is actually very size efficient. It's +somewhat CPU-wasteful, but on the other hand, since you're +really only supposed to do it maybe once a month (and you can +do it during the night), nobody really seems to care.</tt></pre> +</div></div> +<div class="paragraph"><p>Nice Engineering Touch, there. Find when it doesn’t matter, and +proclaim it a non-issue. Good style too!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> So, just to repeat to see if I'm following, we start by + getting a list of the objects we want to pack, we sort it by + this heuristic (basically lexicographically on the tuple + (type, basename, size)).</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Then we walk through this list, and calculate a delta of +each object against the last n (tunable parameter) objects, +and pick the smallest of these deltas.</tt></pre> +</div></div> +<div class="paragraph"><p>Vastly simplified, but the essence is there!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Correct.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> And then once we have picked a delta or fulltext to + represent each object, we re-sort by recency, and write them + out in that order.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Yup. Some other small details:</tt></pre> +</div></div> +<div class="paragraph"><p>And of course there is the "Other Shoe" Factor too.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> - We limit the delta depth to another magic value (right + now both the window and delta depth magic values are just "10")</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Hrm, my intuition is that you'd end up with really _bad_ IO + patterns, because the things you want are near by, but to + actually reconstruct them you may have to jump all over in + random ways.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> - When we write out a delta, and we haven't yet written + out the object it is a delta against, we write out the base + object first. And no, when we reconstruct them, we actually + get nice IO patterns, because: + - larger objects tend to be "more recent" (Linus' law: files grow) + - we actively try to generate deltas from a larger object to a + smaller one + - this means that the top-of-tree very seldom has deltas + (i.e. deltas in _practice_ are "backwards deltas")</tt></pre> +</div></div> +<div class="paragraph"><p>Again, we should reread that whole paragraph. Not just because +Linus has slipped Linus’s Law in there on us, but because it is +important. Let’s make sure we clarify some of the points here:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> So the point is just that in practice, delta order and + recency order match each other quite well.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Yes. There's another nice side to this (and yes, it was + designed that way ;): + - the reason we generate deltas against the larger object is + actually a big space saver too!</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Hmm, but your last comment (if "we haven't yet written out + the object it is a delta against, we write out the base object + first"), seems like it would make these facts mostly + irrelevant because even if in practice you would not have to + wander around much, in fact you just brute-force say that in + the cases where you might have to wander, don't do that :-)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Yes and no. Notice the rule: we only write out the base + object first if the delta against it was more recent. That + means that you can actually have deltas that refer to a base + object that is _not_ close to the delta object, but that only + happens when the delta is needed to generate an _old_ object.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> See?</tt></pre> +</div></div> +<div class="paragraph"><p>Yeah, no. I missed that on the first two or three readings myself.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> This keeps the front of the pack dense. The front of the + pack never contains data that isn't relevant to a "recent" + object. The size optimization comes from our use of xdelta + (but is true for many other delta algorithms): removing data + is cheaper (in size) than adding data.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>When you remove data, you only need to say "copy bytes n--m". +In contrast, in a delta that _adds_ data, you have to say "add +these bytes: 'actual data goes here'"</tt></pre> +</div></div> +<div class="ulist"><ul> +<li> +<p> +njs` has quit: Read error: 104 (Connection reset by peer) +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Uhhuh. I hope I didn't blow njs` mind.</tt></pre> +</div></div> +</li> +<li> +<p> +njs` has joined channel #git +</p> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> :)</tt></pre> +</div></div> +</li> +</ul></div> +<div class="paragraph"><p>The silent observers are amused. Of course.</p></div> +<div class="paragraph"><p>And as if njs` was expected to be omniscient:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> njs - did you miss anything?</tt></pre> +</div></div> +<div class="paragraph"><p>OK, I’ll spell it out. That’s Geek Humor. If njs` was not actually +connected for a little bit there, how would he know if missed anything +while he was disconnected? He’s a benevolent dictator with a sense of +humor! Well noted!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Stupid router. Or gremlins, or whatever.</tt></pre> +</div></div> +<div class="paragraph"><p>It’s a cheap shot at Cisco. Take 'em when you can.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Yes and no. Notice the rule: we only write out the base + object first if the delta against it was more recent.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>I'm getting lost in all these orders, let me re-read :-) +So the write-out order is from most recent to least recent? +(Conceivably it could be the opposite way too, I'm not sure if +we've said) though my connection back at home is logging, so I +can just read what you said there :-)</tt></pre> +</div></div> +<div class="paragraph"><p>And for those of you paying attention, the Omniscient Trick has just +been detailed!</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Yes, we always write out most recent first</tt></pre> +</div></div> +<div class="paragraph"><p>For the other record:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> njs`: http://pastebin.com/547965</tt></pre> +</div></div> +<div class="paragraph"><p>The 'net never forgets, so that should be good until the end of time.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> And, yeah, I got the part about deeper-in-history stuff + having worse IO characteristics, one sort of doesn't care.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> With the caveat that if the "most recent" needs an older + object to delta against (hey, shrinking sometimes does + happen), we write out the old object with the delta.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> (if only it happened more...)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Anyway, the pack-file could easily be denser still, but + because it's used both for streaming (the git protocol) and + for on-disk, it has a few pessimizations.</tt></pre> +</div></div> +<div class="paragraph"><p>Actually, it is a made-up word. But it is a made-up word being +used as setup for a later optimization, which is a real word:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> In particular, while the pack-file is then compressed, + it's compressed just one object at a time, so the actual + compression factor is less than it could be in theory. But it + means that it's all nice random-access with a simple index to + do "object name->location in packfile" translation.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> I'm assuming the real win for delta-ing large->small is + more homogeneous statistics for gzip to run over?</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>(You have to put the bytes in one place or another, but +putting them in a larger blob wins on compression)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Actually, what is the compression strategy -- each delta +individually gzipped, the whole file gzipped, somewhere in +between, no compression at all, ....?</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Right.</tt></pre> +</div></div> +<div class="paragraph"><p>Reality IRC sets in. For example:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><pasky> I'll read the rest in the morning, I really have to go + sleep or there's no hope whatsoever for me at the today's + exam... g'nite all.</tt></pre> +</div></div> +<div class="paragraph"><p>Heh.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> pasky: g'nite</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> pasky: 'luck</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Right: large->small matters exactly because of compression + behaviour. If it was non-compressed, it probably wouldn't make + any difference.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> yeah</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Anyway: I'm not even trying to claim that the pack-files + are perfect, but they do tend to have a nice balance of + density vs ease-of use.</tt></pre> +</div></div> +<div class="paragraph"><p>Gasp! OK, saved. That’s a fair Engineering trade off. Close call! +In fact, Linus reflects on some Basic Engineering Fundamentals, +design options, etc.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> More importantly, they allow git to still _conceptually_ + never deal with deltas at all, and be a "whole object" store.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Which has some problems (we discussed bad huge-file +behaviour on the git lists the other day), but it does mean +that the basic git concepts are really really simple and +straightforward.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>It's all been quite stable.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Which I think is very much a result of having very simple +basic ideas, so that there's never any confusion about what's +going on.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>Bugs happen, but they are "simple" bugs. And bugs that +actually get some object store detail wrong are almost always +so obvious that they never go anywhere.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> Yeah.</tt></pre> +</div></div> +<div class="paragraph"><p>Nuff said.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><linus> Anyway. I'm off for bed. It's not 6AM here, but I've got + three kids, and have to get up early in the morning to send + them off. I need my beauty sleep.</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> :-)</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt><njs`> appreciate the infodump, I really was failing to find the + details on git packs :-)</tt></pre> +</div></div> +<div class="paragraph"><p>And now you know the rest of the story.</p></div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2011-11-15 13:45:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/pack-protocol.html b/technical/pack-protocol.html new file mode 100644 index 0000000..a980cc4 --- /dev/null +++ b/technical/pack-protocol.html
@@ -0,0 +1,1098 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Packfile transfer protocols</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Packfile transfer protocols</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>Git supports transferring data in packfiles over the ssh://, git:// and +file:// transports. There exist two sets of protocols, one for pushing +data from a client to a server and another for fetching data from a +server to a client. All three transports (ssh, git, file) use the same +protocol to transfer data.</p></div> +<div class="paragraph"><p>The processes invoked in the canonical Git implementation are <em>upload-pack</em> +on the server side and <em>fetch-pack</em> on the client side for fetching data; +then <em>receive-pack</em> on the server and <em>send-pack</em> on the client for pushing +data. The protocol functions to have a server tell a client what is +currently on the server, then for the two to negotiate the smallest amount +of data to send in order to fully update one or the other.</p></div> +</div> +</div> +<h2 id="_transports">Transports</h2> +<div class="sectionbody"> +<div class="paragraph"><p>There are three transports over which the packfile protocol is +initiated. The Git transport is a simple, unauthenticated server that +takes the command (almost always <em>upload-pack</em>, though Git +servers can be configured to be globally writable, in which <em>receive- +pack</em> initiation is also allowed) with which the client wishes to +communicate and executes it and connects it to the requesting +process.</p></div> +<div class="paragraph"><p>In the SSH transport, the client just runs the <em>upload-pack</em> +or <em>receive-pack</em> process on the server over the SSH protocol and then +communicates with that invoked process over the SSH connection.</p></div> +<div class="paragraph"><p>The file:// transport runs the <em>upload-pack</em> or <em>receive-pack</em> +process locally and communicates with it over a pipe.</p></div> +</div> +<h2 id="_git_transport">Git Transport</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The Git transport starts off by sending the command and repository +on the wire using the pkt-line format, followed by a NUL byte and a +hostname parameter, terminated by a NUL byte.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>0032git-upload-pack /project.git\0host=myserver.com\0</tt></pre> +</div></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>git-proto-request = request-command SP pathname NUL [ host-parameter NUL ] +request-command = "git-upload-pack" / "git-receive-pack" / + "git-upload-archive" ; case sensitive +pathname = *( %x01-ff ) ; exclude NUL +host-parameter = "host=" hostname [ ":" port ]</tt></pre> +</div></div> +<div class="paragraph"><p>Only host-parameter is allowed in the git-proto-request. Clients +MUST NOT attempt to send additional parameters. It is used for the +git-daemon name based virtual hosting. See --interpolated-path +option to git daemon, with the %H/%CH format characters.</p></div> +<div class="paragraph"><p>Basically what the Git client is doing to connect to an <em>upload-pack</em> +process on the server side over the Git protocol is this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ echo -e -n \ + "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" | + nc -v example.com 9418</tt></pre> +</div></div> +<div class="paragraph"><p>If the server refuses the request for some reasons, it could abort +gracefully with an error message.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> error-line = PKT-LINE("ERR" SP explanation-text)</tt></pre> +</div></div> +</div> +<h2 id="_ssh_transport">SSH Transport</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Initiating the upload-pack or receive-pack processes over SSH is +executing the binary on the server via SSH remote execution. +It is basically equivalent to running this:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ ssh git.example.com "git-upload-pack '/project.git'"</tt></pre> +</div></div> +<div class="paragraph"><p>For a server to support Git pushing and pulling for a given user over +SSH, that user needs to be able to execute one or both of those +commands via the SSH shell that they are provided on login. On some +systems, that shell access is limited to only being able to run those +two commands, or even just one of them.</p></div> +<div class="paragraph"><p>In an ssh:// format URI, it’s absolute in the URI, so the <em>/</em> after +the host name (or port number) is sent as an argument, which is then +read by the remote git-upload-pack exactly as is, so it’s effectively +an absolute path in the remote filesystem.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> git clone ssh://user@example.com/project.git + | + v +ssh user@example.com "git-upload-pack '/project.git'"</tt></pre> +</div></div> +<div class="paragraph"><p>In a "user@host:path" format URI, its relative to the user’s home +directory, because the Git client will run:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> git clone user@example.com:project.git + | + v +ssh user@example.com "git-upload-pack 'project.git'"</tt></pre> +</div></div> +<div class="paragraph"><p>The exception is if a <em>~</em> is used, in which case +we execute it without the leading <em>/</em>.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> ssh://user@example.com/~alice/project.git, + | + v +ssh user@example.com "git-upload-pack '~alice/project.git'"</tt></pre> +</div></div> +<div class="paragraph"><p>A few things to remember here:</p></div> +<div class="ulist"><ul> +<li> +<p> +The "command name" is spelled with dash (e.g. git-upload-pack), but + this can be overridden by the client; +</p> +</li> +<li> +<p> +The repository path is always quoted with single quotes. +</p> +</li> +</ul></div> +</div> +<h2 id="_fetching_data_from_a_server">Fetching Data From a Server</h2> +<div class="sectionbody"> +<div class="paragraph"><p>When one Git repository wants to get data that a second repository +has, the first can <em>fetch</em> from the second. This operation determines +what data the server has that the client does not then streams that +data down to the client in packfile format.</p></div> +</div> +<h2 id="_reference_discovery">Reference Discovery</h2> +<div class="sectionbody"> +<div class="paragraph"><p>When the client initially connects the server will immediately respond +with a listing of each reference it has (all branches and tags) along +with the object name that each reference currently points to.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ echo -e -n "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" | + nc -v example.com 9418 +00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack + side-band side-band-64k ofs-delta shallow no-progress include-tag +00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration +003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master +003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9 +003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0 +003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{} +0000</tt></pre> +</div></div> +<div class="paragraph"><p>Server SHOULD terminate each non-flush line using LF ("\n") terminator; +client MUST NOT complain if there is no terminator.</p></div> +<div class="paragraph"><p>The returned response is a pkt-line stream describing each ref and +its current value. The stream MUST be sorted by name according to +the C locale ordering.</p></div> +<div class="paragraph"><p>If HEAD is a valid ref, HEAD MUST appear as the first advertised +ref. If HEAD is not a valid ref, HEAD MUST NOT appear in the +advertisement list at all, but other refs may still appear.</p></div> +<div class="paragraph"><p>The stream MUST include capability declarations behind a NUL on the +first ref. The peeled value of a ref (that is "ref^{}") MUST be +immediately after the ref itself, if presented. A conforming server +MUST peel the ref if it’s an annotated tag.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> advertised-refs = (no-refs / list-of-refs) + flush-pkt + + no-refs = PKT-LINE(zero-id SP "capabilities^{}" + NUL capability-list LF) + + list-of-refs = first-ref *other-ref + first-ref = PKT-LINE(obj-id SP refname + NUL capability-list LF) + + other-ref = PKT-LINE(other-tip / other-peeled) + other-tip = obj-id SP refname LF + other-peeled = obj-id SP refname "^{}" LF + + capability-list = capability *(SP capability) + capability = 1*(LC_ALPHA / DIGIT / "-" / "_") + LC_ALPHA = %x61-7A</tt></pre> +</div></div> +<div class="paragraph"><p>Server and client MUST use lowercase for obj-id, both MUST treat obj-id +as case-insensitive.</p></div> +<div class="paragraph"><p>See protocol-capabilities.txt for a list of allowed server capabilities +and descriptions.</p></div> +</div> +<h2 id="_packfile_negotiation">Packfile Negotiation</h2> +<div class="sectionbody"> +<div class="paragraph"><p>After reference and capabilities discovery, the client can decide to +terminate the connection by sending a flush-pkt, telling the server it can +now gracefully terminate, and disconnect, when it does not need any pack +data. This can happen with the ls-remote command, and also can happen when +the client already is up-to-date.</p></div> +<div class="paragraph"><p>Otherwise, it enters the negotiation phase, where the client and +server determine what the minimal packfile necessary for transport is, +by telling the server what objects it wants, its shallow objects +(if any), and the maximum commit depth it wants (if any). The client +will also send a list of the capabilities it wants to be in effect, +out of what the server said it could do with the first <em>want</em> line.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> upload-request = want-list + *shallow-line + *1depth-request + flush-pkt + + want-list = first-want + *additional-want + + shallow-line = PKT_LINE("shallow" SP obj-id) + + depth-request = PKT_LINE("deepen" SP depth) + + first-want = PKT-LINE("want" SP obj-id SP capability-list LF) + additional-want = PKT-LINE("want" SP obj-id LF) + + depth = 1*DIGIT</tt></pre> +</div></div> +<div class="paragraph"><p>Clients MUST send all the obj-ids it wants from the reference +discovery phase as <em>want</em> lines. Clients MUST send at least one +<em>want</em> command in the request body. Clients MUST NOT mention an +obj-id in a <em>want</em> command which did not appear in the response +obtained through ref discovery.</p></div> +<div class="paragraph"><p>The client MUST write all obj-ids which it only has shallow copies +of (meaning that it does not have the parents of a commit) as +<em>shallow</em> lines so that the server is aware of the limitations of +the client’s history. Clients MUST NOT mention an obj-id which +it does not know exists on the server.</p></div> +<div class="paragraph"><p>The client now sends the maximum commit history depth it wants for +this transaction, which is the number of commits it wants from the +tip of the history, if any, as a <em>deepen</em> line. A depth of 0 is the +same as not making a depth request. The client does not want to receive +any commits beyond this depth, nor objects needed only to complete +those commits. Commits whose parents are not received as a result are +defined as shallow and marked as such in the server. This information +is sent back to the client in the next step.</p></div> +<div class="paragraph"><p>Once all the <em>want’s and 'shallow’s (and optional 'deepen</em>) are +transferred, clients MUST send a flush-pkt, to tell the server side +that it is done sending the list.</p></div> +<div class="paragraph"><p>Otherwise, if the client sent a positive depth request, the server +will determine which commits will and will not be shallow and +send this information to the client. If the client did not request +a positive depth, this step is skipped.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> shallow-update = *shallow-line + *unshallow-line + flush-pkt + + shallow-line = PKT-LINE("shallow" SP obj-id) + + unshallow-line = PKT-LINE("unshallow" SP obj-id)</tt></pre> +</div></div> +<div class="paragraph"><p>If the client has requested a positive depth, the server will compute +the set of commits which are no deeper than the desired depth. The set +of commits start at the client’s wants.</p></div> +<div class="paragraph"><p>The server writes <em>shallow</em> lines for each +commit whose parents will not be sent as a result. The server writes +an <em>unshallow</em> line for each commit which the client has indicated is +shallow, but is no longer shallow at the currently requested depth +(that is, its parents will now be sent). The server MUST NOT mark +as unshallow anything which the client has not indicated was shallow.</p></div> +<div class="paragraph"><p>Now the client will send a list of the obj-ids it has using <em>have</em> +lines, so the server can make a packfile that only contains the objects +that the client needs. In multi_ack mode, the canonical implementation +will send up to 32 of these at a time, then will send a flush-pkt. The +canonical implementation will skip ahead and send the next 32 immediately, +so that there is always a block of 32 "in-flight on the wire" at a time.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> upload-haves = have-list + compute-end + + have-list = *have-line + have-line = PKT-LINE("have" SP obj-id LF) + compute-end = flush-pkt / PKT-LINE("done")</tt></pre> +</div></div> +<div class="paragraph"><p>If the server reads <em>have</em> lines, it then will respond by ACKing any +of the obj-ids the client said it had that the server also has. The +server will ACK obj-ids differently depending on which ack mode is +chosen by the client.</p></div> +<div class="paragraph"><p>In multi_ack mode:</p></div> +<div class="ulist"><ul> +<li> +<p> +the server will respond with <em>ACK obj-id continue</em> for any common + commits. +</p> +</li> +<li> +<p> +once the server has found an acceptable common base commit and is + ready to make a packfile, it will blindly ACK all <em>have</em> obj-ids + back to the client. +</p> +</li> +<li> +<p> +the server will then send a <em>NACK</em> and then wait for another response + from the client - either a <em>done</em> or another list of <em>have</em> lines. +</p> +</li> +</ul></div> +<div class="paragraph"><p>In multi_ack_detailed mode:</p></div> +<div class="ulist"><ul> +<li> +<p> +the server will differentiate the ACKs where it is signaling + that it is ready to send data with <em>ACK obj-id ready</em> lines, and + signals the identified common commits with <em>ACK obj-id common</em> lines. +</p> +</li> +</ul></div> +<div class="paragraph"><p>Without either multi_ack or multi_ack_detailed:</p></div> +<div class="ulist"><ul> +<li> +<p> +upload-pack sends "ACK obj-id" on the first common object it finds. + After that it says nothing until the client gives it a "done". +</p> +</li> +<li> +<p> +upload-pack sends "NAK" on a flush-pkt if no common object + has been found yet. If one has been found, and thus an ACK + was already sent, it’s silent on the flush-pkt. +</p> +</li> +</ul></div> +<div class="paragraph"><p>After the client has gotten enough ACK responses that it can determine +that the server has enough information to send an efficient packfile +(in the canonical implementation, this is determined when it has received +enough ACKs that it can color everything left in the --date-order queue +as common with the server, or the --date-order queue is empty), or the +client determines that it wants to give up (in the canonical implementation, +this is determined when the client sends 256 <em>have</em> lines without getting +any of them ACKed by the server - meaning there is nothing in common and +the server should just send all of its objects), then the client will send +a <em>done</em> command. The <em>done</em> command signals to the server that the client +is ready to receive its packfile data.</p></div> +<div class="paragraph"><p>However, the 256 limit <strong>only</strong> turns on in the canonical client +implementation if we have received at least one "ACK %s continue" +during a prior round. This helps to ensure that at least one common +ancestor is found before we give up entirely.</p></div> +<div class="paragraph"><p>Once the <em>done</em> line is read from the client, the server will either +send a final <em>ACK obj-id</em> or it will send a <em>NAK</em>. The server only sends +ACK after <em>done</em> if there is at least one common base and multi_ack or +multi_ack_detailed is enabled. The server always sends NAK after <em>done</em> +if there is no common base found.</p></div> +<div class="paragraph"><p>Then the server will start sending its packfile data.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> server-response = *ack_multi ack / nak + ack_multi = PKT-LINE("ACK" SP obj-id ack_status LF) + ack_status = "continue" / "common" / "ready" + ack = PKT-LINE("ACK SP obj-id LF) + nak = PKT-LINE("NAK" LF)</tt></pre> +</div></div> +<div class="paragraph"><p>A simple clone may look like this (with no <em>have</em> lines):</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \ + side-band-64k ofs-delta\n + C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n + C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n + C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n + C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n + C: 0000 + C: 0009done\n + + S: 0008NAK\n + S: [PACKFILE]</tt></pre> +</div></div> +<div class="paragraph"><p>An incremental update (fetch) response might look like this:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_ack \ + side-band-64k ofs-delta\n + C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n + C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n + C: 0000 + C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n + C: [30 more have lines] + C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n + C: 0000 + + S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n + S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n + S: 0008NAK\n + + C: 0009done\n + + S: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n + S: [PACKFILE]</tt></pre> +</div></div> +</div> +<h2 id="_packfile_data">Packfile Data</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Now that the client and server have finished negotiation about what +the minimal amount of data that needs to be sent to the client is, the server +will construct and send the required data in packfile format.</p></div> +<div class="paragraph"><p>See pack-format.txt for what the packfile itself actually looks like.</p></div> +<div class="paragraph"><p>If <em>side-band</em> or <em>side-band-64k</em> capabilities have been specified by +the client, the server will send the packfile data multiplexed.</p></div> +<div class="paragraph"><p>Each packet starting with the packet-line length of the amount of data +that follows, followed by a single byte specifying the sideband the +following data is coming in on.</p></div> +<div class="paragraph"><p>In <em>side-band</em> mode, it will send up to 999 data bytes plus 1 control +code, for a total of up to 1000 bytes in a pkt-line. In <em>side-band-64k</em> +mode it will send up to 65519 data bytes plus 1 control code, for a +total of up to 65520 bytes in a pkt-line.</p></div> +<div class="paragraph"><p>The sideband byte will be a <em>1</em>, <em>2</em> or a <em>3</em>. Sideband <em>1</em> will contain +packfile data, sideband <em>2</em> will be used for progress information that the +client will generally print to stderr and sideband <em>3</em> is used for error +information.</p></div> +<div class="paragraph"><p>If no <em>side-band</em> capability was specified, the server will stream the +entire packfile without multiplexing.</p></div> +</div> +<h2 id="_pushing_data_to_a_server">Pushing Data To a Server</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Pushing data to a server will invoke the <em>receive-pack</em> process on the +server, which will allow the client to tell it which references it should +update and then send all the data the server will need for those new +references to be complete. Once all the data is received and validated, +the server will then update its references to what the client specified.</p></div> +</div> +<h2 id="_authentication">Authentication</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The protocol itself contains no authentication mechanisms. That is to be +handled by the transport, such as SSH, before the <em>receive-pack</em> process is +invoked. If <em>receive-pack</em> is configured over the Git transport, those +repositories will be writable by anyone who can access that port (9418) as +that transport is unauthenticated.</p></div> +</div> +<h2 id="_reference_discovery_2">Reference Discovery</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The reference discovery phase is done nearly the same way as it is in the +fetching protocol. Each reference obj-id and name on the server is sent +in packet-line format to the client, followed by a flush-pkt. The only +real difference is that the capability listing is different - the only +possible values are <em>report-status</em>, <em>delete-refs</em> and <em>ofs-delta</em>.</p></div> +</div> +<h2 id="_reference_update_request_and_packfile_transfer">Reference Update Request and Packfile Transfer</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Once the client knows what references the server is at, it can send a +list of reference update requests. For each reference on the server +that it wants to update, it sends a line listing the obj-id currently on +the server, the obj-id the client would like to update it to and the name +of the reference.</p></div> +<div class="paragraph"><p>This list is followed by a flush-pkt and then the packfile that should +contain all the objects that the server will need to complete the new +references.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> update-request = command-list [pack-file] + + command-list = PKT-LINE(command NUL capability-list LF) + *PKT-LINE(command LF) + flush-pkt + + command = create / delete / update + create = zero-id SP new-id SP name + delete = old-id SP zero-id SP name + update = old-id SP new-id SP name + + old-id = obj-id + new-id = obj-id + + pack-file = "PACK" 28*(OCTET)</tt></pre> +</div></div> +<div class="paragraph"><p>If the receiving end does not support delete-refs, the sending end MUST +NOT ask for delete command.</p></div> +<div class="paragraph"><p>The pack-file MUST NOT be sent if the only command used is <em>delete</em>.</p></div> +<div class="paragraph"><p>A pack-file MUST be sent if either create or update command is used, +even if the server already has all the necessary objects. In this +case the client MUST send an empty pack-file. The only time this +is likely to happen is if the client is creating +a new branch or a tag that points to an existing obj-id.</p></div> +<div class="paragraph"><p>The server will receive the packfile, unpack it, then validate each +reference that is being updated that it hasn’t changed while the request +was being processed (the obj-id is still the same as the old-id), and +it will run any update hooks to make sure that the update is acceptable. +If all of that is fine, the server will then update the references.</p></div> +</div> +<h2 id="_report_status">Report Status</h2> +<div class="sectionbody"> +<div class="paragraph"><p>After receiving the pack data from the sender, the receiver sends a +report if <em>report-status</em> capability is in effect. +It is a short listing of what happened in that update. It will first +list the status of the packfile unpacking as either <em>unpack ok</em> or +<em>unpack [error]</em>. Then it will list the status for each of the references +that it tried to update. Each line is either <em>ok [refname]</em> if the +update was successful, or <em>ng [refname] [error]</em> if the update was not.</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> report-status = unpack-status + 1*(command-status) + flush-pkt + + unpack-status = PKT-LINE("unpack" SP unpack-result LF) + unpack-result = "ok" / error-msg + + command-status = command-ok / command-fail + command-ok = PKT-LINE("ok" SP refname LF) + command-fail = PKT-LINE("ng" SP refname SP error-msg LF) + + error-msg = 1*(OCTECT) ; where not "ok"</tt></pre> +</div></div> +<div class="paragraph"><p>Updates can be unsuccessful for a number of reasons. The reference can have +changed since the reference discovery phase was originally sent, meaning +someone pushed in the meantime. The reference being pushed could be a +non-fast-forward reference and the update hooks or configuration could be +set to not allow that, etc. Also, some references can be updated while others +can be rejected.</p></div> +<div class="paragraph"><p>An example client/server communication might look like this:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> S: 007c74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/local\0report-status delete-refs ofs-delta\n + S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n + S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n + S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n + S: 0000 + + C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n + C: 003e74730d410fcb6603ace96f1dc55ea6196122532d 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n + C: 0000 + C: [PACKDATA] + + S: 000eunpack ok\n + S: 0018ok refs/heads/debug\n + S: 002ang refs/heads/master non-fast-forward\n</tt></pre> +</div></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/pack-protocol.txt b/technical/pack-protocol.txt index d51e20f..f1a51ed 100644 --- a/technical/pack-protocol.txt +++ b/technical/pack-protocol.txt
@@ -117,7 +117,7 @@ - The repository path is always quoted with single quotes. Fetching Data From a Server -=========================== +--------------------------- When one Git repository wants to get data that a second repository has, the first can 'fetch' from the second. This operation determines @@ -134,7 +134,8 @@ $ echo -e -n "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" | nc -v example.com 9418 - 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag + 00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack thin-pack + side-band side-band-64k ofs-delta shallow no-progress include-tag 00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration 003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master 003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9 @@ -421,7 +422,7 @@ Pushing Data To a Server -======================== +------------------------ Pushing data to a server will invoke the 'receive-pack' process on the server, which will allow the client to tell it which references it should
diff --git a/technical/protocol-capabilities.html b/technical/protocol-capabilities.html new file mode 100644 index 0000000..1af78e8 --- /dev/null +++ b/technical/protocol-capabilities.html
@@ -0,0 +1,725 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Git Protocol Capabilities</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Git Protocol Capabilities</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>Servers SHOULD support all capabilities defined in this document.</p></div> +<div class="paragraph"><p>On the very first line of the initial server response of either +receive-pack and upload-pack the first reference is followed by +a NUL byte and then a list of space delimited server capabilities. +These allow the server to declare what it can and cannot support +to the client.</p></div> +<div class="paragraph"><p>Client will then send a space separated list of capabilities it wants +to be in effect. The client MUST NOT ask for capabilities the server +did not say it supports.</p></div> +<div class="paragraph"><p>Server MUST diagnose and abort if capabilities it does not understand +was sent. Server MUST NOT ignore capabilities that client requested +and server advertised. As a consequence of these rules, server MUST +NOT advertise capabilities it does not understand.</p></div> +<div class="paragraph"><p>The <em>report-status</em> and <em>delete-refs</em> capabilities are sent and +recognized by the receive-pack (push to server) process.</p></div> +<div class="paragraph"><p>The <em>ofs-delta</em> capability is sent and recognized by both upload-pack +and receive-pack protocols.</p></div> +<div class="paragraph"><p>All other capabilities are only recognized by the upload-pack (fetch +from server) process.</p></div> +</div> +</div> +<h2 id="_multi_ack">multi_ack</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The <em>multi_ack</em> capability allows the server to return "ACK obj-id +continue" as soon as it finds a commit that it can use as a common +base, between the client’s wants and the client’s have set.</p></div> +<div class="paragraph"><p>By sending this early, the server can potentially head off the client +from walking any further down that particular branch of the client’s +repository history. The client may still need to walk down other +branches, sending have lines for those, until the server has a +complete cut across the DAG, or the client has said "done".</p></div> +<div class="paragraph"><p>Without multi_ack, a client sends have lines in --date-order until +the server has found a common base. That means the client will send +have lines that are already known by the server to be common, because +they overlap in time with another branch that the server hasn’t found +a common base on yet.</p></div> +<div class="paragraph"><p>For example suppose the client has commits in caps that the server +doesn’t and the server has commits in lower case that the client +doesn’t, as in the following diagram:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt> +---- u ---------------------- x + / +----- y + / / +a -- b -- c -- d -- E -- F + \ + +--- Q -- R -- S</tt></pre> +</div></div> +<div class="paragraph"><p>If the client wants x,y and starts out by saying have F,S, the server +doesn’t know what F,S is. Eventually the client says "have d" and +the server sends "ACK d continue" to let the client know to stop +walking down that line (so don’t send c-b-a), but it’s not done yet, +it needs a base for x. The client keeps going with S-R-Q, until a +gets reached, at which point the server has a clear base and it all +ends.</p></div> +<div class="paragraph"><p>Without multi_ack the client would have sent that c-b-a chain anyway, +interleaved with S-R-Q.</p></div> +</div> +<h2 id="_thin_pack">thin-pack</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This capability means that the server can send a <em>thin</em> pack, a pack +which does not contain base objects; if those base objects are available +on client side. Client requests <em>thin-pack</em> capability when it +understands how to "thicken" it by adding required delta bases making +it self-contained.</p></div> +<div class="paragraph"><p>Client MUST NOT request <em>thin-pack</em> capability if it cannot turn a thin +pack into a self-contained pack.</p></div> +</div> +<h2 id="_side_band_side_band_64k">side-band, side-band-64k</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This capability means that server can send, and client understand multiplexed +progress reports and error info interleaved with the packfile itself.</p></div> +<div class="paragraph"><p>These two options are mutually exclusive. A modern client always +favors <em>side-band-64k</em>.</p></div> +<div class="paragraph"><p>Either mode indicates that the packfile data will be streamed broken +up into packets of up to either 1000 bytes in the case of <em>side_band</em>, +or 65520 bytes in the case of <em>side_band_64k</em>. Each packet is made up +of a leading 4-byte pkt-line length of how much data is in the packet, +followed by a 1-byte stream code, followed by the actual data.</p></div> +<div class="paragraph"><p>The stream code can be one of:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>1 - pack data +2 - progress messages +3 - fatal error message just before stream aborts</tt></pre> +</div></div> +<div class="paragraph"><p>The "side-band-64k" capability came about as a way for newer clients +that can handle much larger packets to request packets that are +actually crammed nearly full, while maintaining backward compatibility +for the older clients.</p></div> +<div class="paragraph"><p>Further, with side-band and its up to 1000-byte messages, it’s actually +999 bytes of payload and 1 byte for the stream code. With side-band-64k, +same deal, you have up to 65519 bytes of data and 1 byte for the stream +code.</p></div> +<div class="paragraph"><p>The client MUST send only maximum of one of "side-band" and "side- +band-64k". Server MUST diagnose it as an error if client requests +both.</p></div> +</div> +<h2 id="_ofs_delta">ofs-delta</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Server can send, and client understand PACKv2 with delta referring to +its base by position in pack rather than by an obj-id. That is, they can +send/read OBJ_OFS_DELTA (aka type 6) in a packfile.</p></div> +</div> +<h2 id="_shallow">shallow</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This capability adds "deepen", "shallow" and "unshallow" commands to +the fetch-pack/upload-pack protocol so clients can request shallow +clones.</p></div> +</div> +<h2 id="_no_progress">no-progress</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The client was started with "git clone -q" or something, and doesn’t +want that side band 2. Basically the client just says "I do not +wish to receive stream 2 on sideband, so do not send it to me, and if +you did, I will drop it on the floor anyway". However, the sideband +channel 3 is still used for error responses.</p></div> +</div> +<h2 id="_include_tag">include-tag</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The <em>include-tag</em> capability is about sending annotated tags if we are +sending objects they point to. If we pack an object to the client, and +a tag object points exactly at that object, we pack the tag object too. +In general this allows a client to get all new annotated tags when it +fetches a branch, in a single network connection.</p></div> +<div class="paragraph"><p>Clients MAY always send include-tag, hardcoding it into a request when +the server advertises this capability. The decision for a client to +request include-tag only has to do with the client’s desires for tag +data, whether or not a server had advertised objects in the +refs/tags/* namespace.</p></div> +<div class="paragraph"><p>Servers MUST pack the tags if their referrant is packed and the client +has requested include-tags.</p></div> +<div class="paragraph"><p>Clients MUST be prepared for the case where a server has ignored +include-tag and has not actually sent tags in the pack. In such +cases the client SHOULD issue a subsequent fetch to acquire the tags +that include-tag would have otherwise given the client.</p></div> +<div class="paragraph"><p>The server SHOULD send include-tag, if it supports it, regardless +of whether or not there are tags available.</p></div> +</div> +<h2 id="_report_status">report-status</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The upload-pack process can receive a <em>report-status</em> capability, +which tells it that the client wants a report of what happened after +a packfile upload and reference update. If the pushing client requests +this capability, after unpacking and updating references the server +will respond with whether the packfile unpacked successfully and if +each reference was updated successfully. If any of those were not +successful, it will send back an error message. See pack-protocol.txt +for example messages.</p></div> +</div> +<h2 id="_delete_refs">delete-refs</h2> +<div class="sectionbody"> +<div class="paragraph"><p>If the server sends back the <em>delete-refs</em> capability, it means that +it is capable of accepting a zero-id value as the target +value of a reference update. It is not sent back by the client, it +simply informs the client that it can be sent zero-id values +to delete references.</p></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2011-11-15 13:45:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/protocol-common.html b/technical/protocol-common.html new file mode 100644 index 0000000..9f4aa69 --- /dev/null +++ b/technical/protocol-common.html
@@ -0,0 +1,675 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Documentation Common to Pack and Http Protocols</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Documentation Common to Pack and Http Protocols</h1> +</div> +<div id="content"> +<h2 id="_abnf_notation">ABNF Notation</h2> +<div class="sectionbody"> +<div class="paragraph"><p>ABNF notation as described by RFC 5234 is used within the protocol documents, +except the following replacement core rules are used:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> HEXDIG = DIGIT / "a" / "b" / "c" / "d" / "e" / "f"</tt></pre> +</div></div> +<div class="paragraph"><p>We also define the following common rules:</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> NUL = %x00 + zero-id = 40*"0" + obj-id = 40*(HEXDIGIT) + + refname = "HEAD" + refname /= "refs/" <see discussion below></tt></pre> +</div></div> +<div class="paragraph"><p>A refname is a hierarchical octet string beginning with "refs/" and +not violating the <em>git-check-ref-format</em> command’s validation rules. +More specifically, they:</p></div> +<div class="olist arabic"><ol class="arabic"> +<li> +<p> +They can include slash <tt>/</tt> for hierarchical (directory) + grouping, but no slash-separated component can begin with a + dot <tt>.</tt>. +</p> +</li> +<li> +<p> +They must contain at least one <tt>/</tt>. This enforces the presence of a + category like <tt>heads/</tt>, <tt>tags/</tt> etc. but the actual names are not + restricted. +</p> +</li> +<li> +<p> +They cannot have two consecutive dots <tt>..</tt> anywhere. +</p> +</li> +<li> +<p> +They cannot have ASCII control characters (i.e. bytes whose + values are lower than \040, or \177 <tt>DEL</tt>), space, tilde <tt>~</tt>, + caret <tt>^</tt>, colon <tt>:</tt>, question-mark <tt>?</tt>, asterisk <tt>*</tt>, + or open bracket <tt>[</tt> anywhere. +</p> +</li> +<li> +<p> +They cannot end with a slash <tt>/</tt> nor a dot <tt>.</tt>. +</p> +</li> +<li> +<p> +They cannot end with the sequence <tt>.lock</tt>. +</p> +</li> +<li> +<p> +They cannot contain a sequence <tt>@{</tt>. +</p> +</li> +<li> +<p> +They cannot contain a <tt>\\</tt>. +</p> +</li> +</ol></div> +</div> +<h2 id="_pkt_line_format">pkt-line Format</h2> +<div class="sectionbody"> +<div class="paragraph"><p>Much (but not all) of the payload is described around pkt-lines.</p></div> +<div class="paragraph"><p>A pkt-line is a variable length binary string. The first four bytes +of the line, the pkt-len, indicates the total length of the line, +in hexadecimal. The pkt-len includes the 4 bytes used to contain +the length’s hexadecimal representation.</p></div> +<div class="paragraph"><p>A pkt-line MAY contain binary data, so implementors MUST ensure +pkt-line parsing/formatting routines are 8-bit clean.</p></div> +<div class="paragraph"><p>A non-binary line SHOULD BE terminated by an LF, which if present +MUST be included in the total length.</p></div> +<div class="paragraph"><p>The maximum length of a pkt-line’s data component is 65520 bytes. +Implementations MUST NOT send pkt-line whose length exceeds 65524 +(65520 bytes of payload + 4 bytes of length data).</p></div> +<div class="paragraph"><p>Implementations SHOULD NOT send an empty pkt-line ("0004").</p></div> +<div class="paragraph"><p>A pkt-line with a length field of 0 ("0000"), called a flush-pkt, +is a special case and MUST be handled differently than an empty +pkt-line ("0004").</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> pkt-line = data-pkt / flush-pkt + + data-pkt = pkt-len pkt-payload + pkt-len = 4*(HEXDIG) + pkt-payload = (pkt-len - 4)*(OCTET) + + flush-pkt = "0000"</tt></pre> +</div></div> +<div class="paragraph"><p>Examples (as C-style strings):</p></div> +<div class="listingblock"> +<div class="content"> +<pre><tt> pkt-line actual value + --------------------------------- + "0006a\n" "a\n" + "0005a" "a" + "000bfoobar\n" "foobar\n" + "0004" ""</tt></pre> +</div></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-05-02 15:00:44 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/racy-git.html b/technical/racy-git.html new file mode 100644 index 0000000..fcc026e --- /dev/null +++ b/technical/racy-git.html
@@ -0,0 +1,763 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Use of index and Racy git problem</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Use of index and Racy git problem</h1> +</div> +<div id="content"> +<h2 id="_background">Background</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The index is one of the most important data structures in git. +It represents a virtual working tree state by recording list of +paths and their object names and serves as a staging area to +write out the next tree object to be committed. The state is +"virtual" in the sense that it does not necessarily have to, and +often does not, match the files in the working tree.</p></div> +<div class="paragraph"><p>There are cases git needs to examine the differences between the +virtual working tree state in the index and the files in the +working tree. The most obvious case is when the user asks <tt>git +diff</tt> (or its low level implementation, <tt>git diff-files</tt>) or +<tt>git-ls-files --modified</tt>. In addition, git internally checks +if the files in the working tree are different from what are +recorded in the index to avoid stomping on local changes in them +during patch application, switching branches, and merging.</p></div> +<div class="paragraph"><p>In order to speed up this comparison between the files in the +working tree and the index entries, the index entries record the +information obtained from the filesystem via <tt>lstat(2)</tt> system +call when they were last updated. When checking if they differ, +git first runs <tt>lstat(2)</tt> on the files and compares the result +with this information (this is what was originally done by the +<tt>ce_match_stat()</tt> function, but the current code does it in +<tt>ce_match_stat_basic()</tt> function). If some of these "cached +stat information" fields do not match, git can tell that the +files are modified without even looking at their contents.</p></div> +<div class="paragraph"><p>Note: not all members in <tt>struct stat</tt> obtained via <tt>lstat(2)</tt> +are used for this comparison. For example, <tt>st_atime</tt> obviously +is not useful. Currently, git compares the file type (regular +files vs symbolic links) and executable bits (only for regular +files) from <tt>st_mode</tt> member, <tt>st_mtime</tt> and <tt>st_ctime</tt> +timestamps, <tt>st_uid</tt>, <tt>st_gid</tt>, <tt>st_ino</tt>, and <tt>st_size</tt> members. +With a <tt>USE_STDEV</tt> compile-time option, <tt>st_dev</tt> is also +compared, but this is not enabled by default because this member +is not stable on network filesystems. With <tt>USE_NSEC</tt> +compile-time option, <tt>st_mtim.tv_nsec</tt> and <tt>st_ctim.tv_nsec</tt> +members are also compared, but this is not enabled by default +because in-core timestamps can have finer granularity than +on-disk timestamps, resulting in meaningless changes when an +inode is evicted from the inode cache. See commit 8ce13b0 +of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git +([PATCH] Sync in core time granuality with filesystems, +2005-01-04).</p></div> +</div> +<h2 id="_racy_git">Racy git</h2> +<div class="sectionbody"> +<div class="paragraph"><p>There is one slight problem with the optimization based on the +cached stat information. Consider this sequence:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>: modify 'foo' +$ git update-index 'foo' +: modify 'foo' again, in-place, without changing its size</tt></pre> +</div></div> +<div class="paragraph"><p>The first <tt>update-index</tt> computes the object name of the +contents of file <tt>foo</tt> and updates the index entry for <tt>foo</tt> +along with the <tt>struct stat</tt> information. If the modification +that follows it happens very fast so that the file’s <tt>st_mtime</tt> +timestamp does not change, after this sequence, the cached stat +information the index entry records still exactly match what you +would see in the filesystem, even though the file <tt>foo</tt> is now +different. +This way, git can incorrectly think files in the working tree +are unmodified even though they actually are. This is called +the "racy git" problem (discovered by Pasky), and the entries +that appear clean when they may not be because of this problem +are called "racily clean".</p></div> +<div class="paragraph"><p>To avoid this problem, git does two things:</p></div> +<div class="olist arabic"><ol class="arabic"> +<li> +<p> +When the cached stat information says the file has not been + modified, and the <tt>st_mtime</tt> is the same as (or newer than) + the timestamp of the index file itself (which is the time <tt>git + update-index foo</tt> finished running in the above example), it + also compares the contents with the object registered in the + index entry to make sure they match. +</p> +</li> +<li> +<p> +When the index file is updated that contains racily clean + entries, cached <tt>st_size</tt> information is truncated to zero + before writing a new version of the index file. +</p> +</li> +</ol></div> +<div class="paragraph"><p>Because the index file itself is written after collecting all +the stat information from updated paths, <tt>st_mtime</tt> timestamp of +it is usually the same as or newer than any of the paths the +index contains. And no matter how quick the modification that +follows <tt>git update-index foo</tt> finishes, the resulting +<tt>st_mtime</tt> timestamp on <tt>foo</tt> cannot get a value earlier +than the index file. Therefore, index entries that can be +racily clean are limited to the ones that have the same +timestamp as the index file itself.</p></div> +<div class="paragraph"><p>The callers that want to check if an index entry matches the +corresponding file in the working tree continue to call +<tt>ce_match_stat()</tt>, but with this change, <tt>ce_match_stat()</tt> uses +<tt>ce_modified_check_fs()</tt> to see if racily clean ones are +actually clean after comparing the cached stat information using +<tt>ce_match_stat_basic()</tt>.</p></div> +<div class="paragraph"><p>The problem the latter solves is this sequence:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ git update-index 'foo' +: modify 'foo' in-place without changing its size +: wait for enough time +$ git update-index 'bar'</tt></pre> +</div></div> +<div class="paragraph"><p>Without the latter, the timestamp of the index file gets a newer +value, and falsely clean entry <tt>foo</tt> would not be caught by the +timestamp comparison check done with the former logic anymore. +The latter makes sure that the cached stat information for <tt>foo</tt> +would never match with the file in the working tree, so later +checks by <tt>ce_match_stat_basic()</tt> would report that the index entry +does not match the file and git does not have to fall back on more +expensive <tt>ce_modified_check_fs()</tt>.</p></div> +</div> +<h2 id="_runtime_penalty">Runtime penalty</h2> +<div class="sectionbody"> +<div class="paragraph"><p>The runtime penalty of falling back to <tt>ce_modified_check_fs()</tt> +from <tt>ce_match_stat()</tt> can be very expensive when there are many +racily clean entries. An obvious way to artificially create +this situation is to give the same timestamp to all the files in +the working tree in a large project, run <tt>git update-index</tt> on +them, and give the same timestamp to the index file:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ date >.datestamp +$ git ls-files | xargs touch -r .datestamp +$ git ls-files | git update-index --stdin +$ touch -r .datestamp .git/index</tt></pre> +</div></div> +<div class="paragraph"><p>This will make all index entries racily clean. The linux-2.6 +project, for example, there are over 20,000 files in the working +tree. On my Athlon 64 X2 3800+, after the above:</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>$ /usr/bin/time git diff-files +1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k +0inputs+0outputs (0major+67111minor)pagefaults 0swaps +$ git update-index MAINTAINERS +$ /usr/bin/time git diff-files +0.02user 0.12system 0:00.14elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k +0inputs+0outputs (0major+935minor)pagefaults 0swaps</tt></pre> +</div></div> +<div class="paragraph"><p>Running <tt>git update-index</tt> in the middle checked the racily +clean entries, and left the cached <tt>st_mtime</tt> for all the paths +intact because they were actually clean (so this step took about +the same amount of time as the first <tt>git diff-files</tt>). After +that, they are not racily clean anymore but are truly clean, so +the second invocation of <tt>git diff-files</tt> fully took advantage +of the cached stat information.</p></div> +</div> +<h2 id="_avoiding_runtime_penalty">Avoiding runtime penalty</h2> +<div class="sectionbody"> +<div class="paragraph"><p>In order to avoid the above runtime penalty, post 1.4.2 git used +to have a code that made sure the index file +got timestamp newer than the youngest files in the index when +there are many young files with the same timestamp as the +resulting index file would otherwise would have by waiting +before finishing writing the index file out.</p></div> +<div class="paragraph"><p>I suspected that in practice the situation where many paths in the +index are all racily clean was quite rare. The only code paths +that can record recent timestamp for large number of paths are:</p></div> +<div class="olist arabic"><ol class="arabic"> +<li> +<p> +Initial <tt>git add .</tt> of a large project. +</p> +</li> +<li> +<p> +<tt>git checkout</tt> of a large project from an empty index into an + unpopulated working tree. +</p> +</li> +</ol></div> +<div class="paragraph"><p>Note: switching branches with <tt>git checkout</tt> keeps the cached +stat information of existing working tree files that are the +same between the current branch and the new branch, which are +all older than the resulting index file, and they will not +become racily clean. Only the files that are actually checked +out can become racily clean.</p></div> +<div class="paragraph"><p>In a large project where raciness avoidance cost really matters, +however, the initial computation of all object names in the +index takes more than one second, and the index file is written +out after all that happens. Therefore the timestamp of the +index file will be more than one seconds later than the +youngest file in the working tree. This means that in these +cases there actually will not be any racily clean entry in +the resulting index.</p></div> +<div class="paragraph"><p>Based on this discussion, the current code does not use the +"workaround" to avoid the runtime penalty that does not exist in +practice anymore. This was done with commit 0fc82cff on Aug 15, +2006.</p></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2011-11-15 13:45:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/send-pack-pipeline.html b/technical/send-pack-pipeline.html new file mode 100644 index 0000000..164f1e2 --- /dev/null +++ b/technical/send-pack-pipeline.html
@@ -0,0 +1,646 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Git-send-pack internals</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Git-send-pack internals</h1> +</div> +<div id="content"> +<h2 id="_overall_operation">Overall operation</h2> +<div class="sectionbody"> +<div class="olist arabic"><ol class="arabic"> +<li> +<p> +Connects to the remote side and invokes git-receive-pack. +</p> +</li> +<li> +<p> +Learns what refs the remote has and what commit they point at. + Matches them to the refspecs we are pushing. +</p> +</li> +<li> +<p> +Checks if there are non-fast-forwards. Unlike fetch-pack, + the repository send-pack runs in is supposed to be a superset + of the recipient in fast-forward cases, so there is no need + for want/have exchanges, and fast-forward check can be done + locally. Tell the result to the other end. +</p> +</li> +<li> +<p> +Calls pack_objects() which generates a packfile and sends it + over to the other end. +</p> +</li> +<li> +<p> +If the remote side is new enough (v1.1.0 or later), wait for + the unpack and hook status from the other end. +</p> +</li> +<li> +<p> +Exit with appropriate error codes. +</p> +</li> +</ol></div> +</div> +<h2 id="_pack_objects_pipeline">Pack_objects pipeline</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This function gets one file descriptor (<tt>fd</tt>) which is either a +socket (over the network) or a pipe (local). What’s written to +this fd goes to git-receive-pack to be unpacked.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>send-pack ---> fd ---> receive-pack</tt></pre> +</div></div> +<div class="paragraph"><p>The function pack_objects creates a pipe and then forks. The +forked child execs pack-objects with --revs to receive revision +parameters from its standard input. This process will write the +packfile to the other end.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>send-pack + | + pack_objects() ---> fd ---> receive-pack + | ^ (pipe) + v | + (child)</tt></pre> +</div></div> +<div class="paragraph"><p>The child dup2’s to arrange its standard output to go back to +the other end, and read its standard input to come from the +pipe. After that it exec’s pack-objects. On the other hand, +the parent process, before starting to feed the child pipeline, +closes the reading side of the pipe and fd to receive-pack.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>send-pack + | + pack_objects(parent) + | + v [0] + pack-objects [0] ---> receive-pack</tt></pre> +</div></div> +<div class="paragraph"><p>[jc: the pipeline was much more complex and needed documentation before + I understood an earlier bug, but now it is trivial and straightforward.]</p></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/send-pack-pipeline.txt b/technical/send-pack-pipeline.txt index 681efe4..9b5a0bc 100644 --- a/technical/send-pack-pipeline.txt +++ b/technical/send-pack-pipeline.txt
@@ -1,5 +1,5 @@ -git-send-pack -============= +Git-send-pack internals +======================= Overall operation -----------------
diff --git a/technical/shallow.html b/technical/shallow.html new file mode 100644 index 0000000..1bfbb0b --- /dev/null +++ b/technical/shallow.html
@@ -0,0 +1,632 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Shallow commits</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Shallow commits</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="sidebarblock"> +<div class="sidebar-content"> +<div class="sidebar-title">Definition</div> +<div class="paragraph"><p>Shallow commits do have parents, but not in the shallow +repo, and therefore grafts are introduced pretending that +these commits have no parents.</p></div> +</div></div> +<div class="paragraph"><p>The basic idea is to write the SHA1s of shallow commits into +$GIT_DIR/shallow, and handle its contents like the contents +of $GIT_DIR/info/grafts (with the difference that shallow +cannot contain parent information).</p></div> +<div class="paragraph"><p>This information is stored in a new file instead of grafts, or +even the config, since the user should not touch that file +at all (even throughout development of the shallow clone, it +was never manually edited!).</p></div> +<div class="paragraph"><p>Each line contains exactly one SHA1. When read, a commit_graft +will be constructed, which has nr_parent < 0 to make it easier +to discern from user provided grafts.</p></div> +<div class="paragraph"><p>Since fsck-objects relies on the library to read the objects, +it honours shallow commits automatically.</p></div> +<div class="paragraph"><p>There are some unfinished ends of the whole shallow business:</p></div> +<div class="ulist"><ul> +<li> +<p> +maybe we have to force non-thin packs when fetching into a + shallow repo (ATM they are forced non-thin). +</p> +</li> +<li> +<p> +A special handling of a shallow upstream is needed. At some + stage, upload-pack has to check if it sends a shallow commit, + and it should send that information early (or fail, if the + client does not support shallow repositories). There is no + support at all for this in this patch series. +</p> +</li> +<li> +<p> +Instead of locking $GIT_DIR/shallow at the start, just + the timestamp of it is noted, and when it comes to writing it, + a check is performed if the mtime is still the same, dying if + it is not. +</p> +</li> +<li> +<p> +It is unclear how "push into/from a shallow repo" should behave. +</p> +</li> +<li> +<p> +If you deepen a history, you’d want to get the tags of the + newly stored (but older!) commits. This does not work right now. +</p> +</li> +</ul></div> +<div class="paragraph"><p>To make a shallow clone, you can call "git-clone --depth 20 repo". +The result contains only commit chains with a length of at most 20. +It also writes an appropriate $GIT_DIR/shallow.</p></div> +<div class="paragraph"><p>You can deepen a shallow repository with "git-fetch --depth 20 +repo branch", which will fetch branch from repo, but stop at depth +20, updating $GIT_DIR/shallow.</p></div> +</div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/shallow.txt b/technical/shallow.txt index 559263a..0502a54 100644 --- a/technical/shallow.txt +++ b/technical/shallow.txt
@@ -1,6 +1,12 @@ -Def.: Shallow commits do have parents, but not in the shallow +Shallow commits +=============== + +.Definition +********************************************************* +Shallow commits do have parents, but not in the shallow repo, and therefore grafts are introduced pretending that these commits have no parents. +********************************************************* The basic idea is to write the SHA1s of shallow commits into $GIT_DIR/shallow, and handle its contents like the contents
diff --git a/technical/trivial-merge.html b/technical/trivial-merge.html new file mode 100644 index 0000000..f447354 --- /dev/null +++ b/technical/trivial-merge.html
@@ -0,0 +1,673 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<meta name="generator" content="AsciiDoc 8.5.2" /> +<title>Trivial merge rules</title> +<style type="text/css"> +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #dddddd; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + + +@media print { + div#footer-badges { display: none; } +} + +div#toc { + margin-bottom: 2.5em; +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock-content { + white-space: pre; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } +</style> +<script type="text/javascript"> +/*<+'])'); + // Function that scans the DOM tree for header elements (the DOM2 + // nodeIterator API would be a better technique but not supported by all + // browsers). + var iterate = function (el) { + for (var i = el.firstChild; i != null; i = i.nextSibling) { + if (i.nodeType == 1 /* Node.ELEMENT_NODE */) { + var mo = re.exec(i.tagName); + if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") { + result[result.length] = new TocEntry(i, getText(i), mo[1]-1); + } + iterate(i); + } + } + } + iterate(el); + return result; + } + + var toc = document.getElementById("toc"); + var entries = tocEntries(document.getElementById("content"), toclevels); + for (var i = 0; i < entries.length; ++i) { + var entry = entries[i]; + if (entry.element.id == "") + entry.element.id = "_toc_" + i; + var a = document.createElement("a"); + a.href = "#" + entry.element.id; + a.appendChild(document.createTextNode(entry.text)); + var div = document.createElement("div"); + div.appendChild(a); + div.className = "toclevel" + entry.toclevel; + toc.appendChild(div); + } + if (entries.length == 0) + toc.parentNode.removeChild(toc); +}, + + +///////////////////////////////////////////////////////////////////// +// Footnotes generator +///////////////////////////////////////////////////////////////////// + +/* Based on footnote generation code from: + * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html + */ + +footnotes: function () { + var cont = document.getElementById("content"); + var noteholder = document.getElementById("footnotes"); + var spans = cont.getElementsByTagName("span"); + var refs = {}; + var n = 0; + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnote") { + n++; + // Use [\s\S] in place of . so multi-line matches work. + // Because JavaScript has no s (dotall) regex flag. + note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1]; + noteholder.innerHTML += + "<div class='footnote' id='_footnote_" + n + "'>" + + "<a href='#_footnoteref_" + n + "' title='Return to text'>" + + n + "</a>. " + note + "</div>"; + spans[i].innerHTML = + "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + var id =spans[i].getAttribute("id"); + if (id != null) refs["#"+id] = n; + } + } + if (n == 0) + noteholder.parentNode.removeChild(noteholder); + else { + // Process footnoterefs. + for (i=0; i<spans.length; i++) { + if (spans[i].className == "footnoteref") { + var href = spans[i].getElementsByTagName("a")[0].getAttribute("href"); + href = href.match(/#.*/)[0]; // Because IE return full URL. + n = refs[href]; + spans[i].innerHTML = + "[<a href='#_footnote_" + n + + "' title='View footnote' class='footnote'>" + n + "</a>]"; + } + } + } +} + +} +/*]]>*/ +</script> +</head> +<body> +<div id="header"> +<h1>Trivial merge rules</h1> +</div> +<div id="content"> +<div id="preamble"> +<div class="sectionbody"> +<div class="paragraph"><p>This document describes the outcomes of the trivial merge logic in read-tree.</p></div> +</div> +</div> +<h2 id="_one_way_merge">One-way merge</h2> +<div class="sectionbody"> +<div class="paragraph"><p>This replaces the index with a different tree, keeping the stat info +for entries that don’t change, and allowing -u to make the minimum +required changes to the working tree to have it match.</p></div> +<div class="paragraph"><p>Entries marked <em>+</em> have stat information. Spaces marked <em>*</em> don’t +affect the result.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>index tree result +----------------------- +* (empty) (empty) +(empty) tree tree +index+ tree tree +index+ index index+</tt></pre> +</div></div> +</div> +<h2 id="_two_way_merge">Two-way merge</h2> +<div class="sectionbody"> +<div class="paragraph"><p>It is permitted for the index to lack an entry; this does not prevent +any case from applying.</p></div> +<div class="paragraph"><p>If the index exists, it is an error for it not to match either the old +or the result.</p></div> +<div class="paragraph"><p>If multiple cases apply, the one used is listed first.</p></div> +<div class="paragraph"><p>A result which changes the index is an error if the index is not empty +and not up-to-date.</p></div> +<div class="paragraph"><p>Entries marked <em>+</em> have stat information. Spaces marked <em>*</em> don’t +affect the result.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>case index old new result +------------------------------------- +0/2 (empty) * (empty) (empty) +1/3 (empty) * new new +4/5 index+ (empty) (empty) index+ +6/7 index+ (empty) index index+ +10 index+ index (empty) (empty) +14/15 index+ old old index+ +18/19 index+ old index index+ +20 index+ index new new</tt></pre> +</div></div> +</div> +<h2 id="_three_way_merge">Three-way merge</h2> +<div class="sectionbody"> +<div class="paragraph"><p>It is permitted for the index to lack an entry; this does not prevent +any case from applying.</p></div> +<div class="paragraph"><p>If the index exists, it is an error for it not to match either the +head or (if the merge is trivial) the result.</p></div> +<div class="paragraph"><p>If multiple cases apply, the one used is listed first.</p></div> +<div class="paragraph"><p>A result of "no merge" means that index is left in stage 0, ancest in +stage 1, head in stage 2, and remote in stage 3 (if any of these are +empty, no entry is left for that stage). Otherwise, the given entry is +left in stage 0, and there are no other entries.</p></div> +<div class="paragraph"><p>A result of "no merge" is an error if the index is not empty and not +up-to-date.</p></div> +<div class="paragraph"><p><strong>empty</strong> means that the tree must not have a directory-file conflict + with the entry.</p></div> +<div class="paragraph"><p>For multiple ancestors, a <em>+</em> means that this case applies even if +only one ancestor or remote fits; a <em>^</em> means all of the ancestors +must be the same.</p></div> +<div class="literalblock"> +<div class="content"> +<pre><tt>case ancest head remote result +---------------------------------------- +1 (empty)+ (empty) (empty) (empty) +2ALT (empty)+ *empty* remote remote +2 (empty)^ (empty) remote no merge +3ALT (empty)+ head *empty* head +3 (empty)^ head (empty) no merge +4 (empty)^ head remote no merge +5ALT * head head head +6 ancest+ (empty) (empty) no merge +8 ancest^ (empty) ancest no merge +7 ancest+ (empty) remote no merge +10 ancest^ ancest (empty) no merge +9 ancest+ head (empty) no merge +16 anc1/anc2 anc1 anc2 no merge +13 ancest+ head ancest head +14 ancest+ ancest remote remote +11 ancest+ head remote no merge</tt></pre> +</div></div> +<div class="paragraph"><p>Only #2ALT and #3ALT use <strong>empty</strong>, because these are the only cases +where there can be conflicts that didn’t exist before. Note that we +allow directory-file conflicts between things in different stages +after the trivial merge.</p></div> +<div class="paragraph"><p>A possible alternative for #6 is (empty), which would make it like +#1. This is not used, due to the likelihood that it arises due to +moving the file to multiple different locations or moving and deleting +it in different branches.</p></div> +<div class="paragraph"><p>Case #1 is included for completeness, and also in case we decide to +put on <em>+</em> markings; any path that is never mentioned at all isn’t +handled.</p></div> +<div class="paragraph"><p>Note that #16 is when both #13 and #14 apply; in this case, we refuse +the trivial merge, because we can’t tell from this data which is +right. This is a case of a reverted patch (in some direction, maybe +multiple times), and the right answer depends on looking at crossings +of history or common ancestors of the ancestors.</p></div> +<div class="paragraph"><p>Note that, between #6, #7, #9, and #11, all cases not otherwise +covered are handled in this table.</p></div> +<div class="paragraph"><p>For #8 and #10, there is alternative behavior, not currently +implemented, where the result is (empty). As currently implemented, +the automatic merge will generally give this effect.</p></div> +</div> +</div> +<div id="footnotes"><hr /></div> +<div id="footer"> +<div id="footer-text"> +Last updated 2012-11-20 13:06:02 PDT +</div> +</div> +</body> +</html>
diff --git a/technical/trivial-merge.txt b/technical/trivial-merge.txt index 24c8410..c79d4a7 100644 --- a/technical/trivial-merge.txt +++ b/technical/trivial-merge.txt
@@ -74,24 +74,24 @@ only one ancestor or remote fits; a '^' means all of the ancestors must be the same. -case ancest head remote result ----------------------------------------- -1 (empty)+ (empty) (empty) (empty) -2ALT (empty)+ *empty* remote remote -2 (empty)^ (empty) remote no merge -3ALT (empty)+ head *empty* head -3 (empty)^ head (empty) no merge -4 (empty)^ head remote no merge -5ALT * head head head -6 ancest+ (empty) (empty) no merge -8 ancest^ (empty) ancest no merge -7 ancest+ (empty) remote no merge -10 ancest^ ancest (empty) no merge -9 ancest+ head (empty) no merge -16 anc1/anc2 anc1 anc2 no merge -13 ancest+ head ancest head -14 ancest+ ancest remote remote -11 ancest+ head remote no merge + case ancest head remote result + ---------------------------------------- + 1 (empty)+ (empty) (empty) (empty) + 2ALT (empty)+ *empty* remote remote + 2 (empty)^ (empty) remote no merge + 3ALT (empty)+ head *empty* head + 3 (empty)^ head (empty) no merge + 4 (empty)^ head remote no merge + 5ALT * head head head + 6 ancest+ (empty) (empty) no merge + 8 ancest^ (empty) ancest no merge + 7 ancest+ (empty) remote no merge + 10 ancest^ ancest (empty) no merge + 9 ancest+ head (empty) no merge + 16 anc1/anc2 anc1 anc2 no merge + 13 ancest+ head ancest head + 14 ancest+ ancest remote remote + 11 ancest+ head remote no merge Only #2ALT and #3ALT use *empty*, because these are the only cases where there can be conflicts that didn't exist before. Note that we